分类目录:《系统学习Python》总目录


闭包函数(带有外围def作用域引用和嵌套的def)常常可以实现相同的效果,特别是用于像被装饰的最初咱数这样的静态数据时。然而在下面这个例子中,我们也需要外层作用域中的一个计数器,它随着每次调用而改变,而这在Python2.X中是不可能的。在Python2.X中,我们仍可以依据前面文章使用的类和属性,或选择其他方案。使用声明把状态变量移出到全局作用域是一个备选项,并且在Python2.X和Python3.X中都能够工作:

calls = 0

def tracer(func):
    def wrapper(*args, **kwargs):
        global calls
        calls += 1
        print('call %s to %s' % (calls, func.__name__))
        return func(*args, **kwargs)
    return wrapper

@tracer
def spam(a, b, c):
    print(a + b + c)

@tracer
def eggs(s, y):
    print(x ** y)

span(1, 2, 3)
span(a=4, b=5, c=6)
eggs(2, 16)
eggs(4, y=4)

遗憾的是,把计数器移出到共同的全局作用域会允许像这样修改它们,这也意味着它们将为每个被包装函数所共享。和类实例属性不同,全局计数器是跨程序的,而不是针对每个函数的一一对于任何跟踪的函数调用,计数器都会递增。如果你比较这个版本与前一个版本的输出,就可以看出其中的区别一一单个并共享的全局调用计数器在每个被装饰函数调用时都会更新,这是不对的:

参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.