我在两个不同的装饰器中创建了两个变量,一个装饰器工作正常,但另一个显示错误。
def running_average(func):
data = {'total': 0, 'count': 0}
def wrapper(*args, **kwargs):
print(data)
val = func(*args, **kwargs)
data['total'] += val
data['count'] += 1
print('Average of {} so far: {:.01f}'.format(func.__name__,
data['total']/data['count']))
return func(*args, **kwargs)
return wrapper
@running_average
def foo(x):
return x + 2
此foo函数有效。
def countcalls(func):
count = 0
print(count)
def wrapper(*args, **kwargs):
print(count)
count += 1
print('# of calls: {}'.format(count))
return func(*args, **kwargs)
return wrapper
@countcalls
def boo(x):
return x + 2
但是此boo
函数显示错误:UnboundLocalError: local variable 'count' referenced before assignment
。
据我了解,这两个函数遵循相同的模式。在两个装饰器中,在装饰器中定义了一个变量,并且在包装函数中使用了该变量。但是,此foo
函数工作正常,但此boo
函数无效。我想知道是什么原因?
答案 0 :(得分:2)
区别在于,在第一个示例中,名称data
始终引用同一对象;它永远不会重新分配。字典data
所引用的字典本身是已变异的(已更改),但始终是同一对象。
相反,在第二个示例中执行count += 1
时,这会更改名称count
所引用的值。这使count
成为局部变量。当解释器看到此消息时,它会注意到您在分配给本地变量count
之前先引用了它,但失败了。
解决方案是通过声明count
来告诉解释器使用封闭范围中的nonlocal
def countcalls(func):
count = 0
print(count)
def wrapper(*args, **kwargs):
nonlocal
print(count)
count += 1
print('# of calls: {}'.format(count))
return func(*args, **kwargs)
return wrapper