def call_counter(func):
call_count = 0
def wrapper(*args, **kwargs):
nonlocal call_count
call_count += 1
with open('function_call_log.txt', 'a') as f:
f.write(f"Call {call_count}: Args: {args}, Kwargs: {kwargs}\n")
return func(*args, **kwargs)
return wrapper
@call_counter
def sample_function(*args, **kwargs):
print("Inside sample function")
return sum(args) if args else 0
闭包在这个装饰器实现过程中的作用和原理:
- 作用:
- 数据隔离与保护:闭包中的
call_count
变量对于外部代码来说是隐藏的,只有wrapper
函数可以访问和修改它,这样就避免了全局变量带来的命名冲突问题,同时保护了这个计数器变量不被随意篡改。
- 状态保持:
call_count
变量在多次调用wrapper
函数时保持其状态,使得每次调用sample_function
(被装饰函数)时,call_count
能正确累加,实现调用次数的统计。
- 原理:
- 当
call_counter
装饰器函数被调用时,它定义了一个局部变量call_count
和内部函数wrapper
。
- 内部函数
wrapper
在其定义时,会记住其所在的词法环境,即包含call_count
变量的环境。即使call_counter
函数执行完毕返回,wrapper
函数仍然持有对这个环境的引用,所以call_count
变量不会被销毁。
- 每次调用
wrapper
函数时,它可以访问并修改call_count
变量,同时将调用参数记录到日志文件中,然后调用原始函数func
并返回其结果。这里使用nonlocal
关键字来声明call_count
不是wrapper
函数的局部变量,而是来自外层(但非全局)作用域,以便能够正确修改它的值。