装饰器运行错误:“ UnboundLocalError:分配前引用了本地变量'count'”

时间:2019-07-24 13:50:43

标签: python decorator

我在两个不同的装饰器中创建了两个变量,一个装饰器工作正常,但另一个显示错误。

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函数无效。我想知道是什么原因?

1 个答案:

答案 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