分类目录:《系统学习Python》总目录
文章《系统学习Python——装饰器:函数装饰器-[跟踪调用]》最后一个例子引发了一个重要的问题。函数装饰器有各种方案来保持装饰的时候所提供的状态信息,以便在实际函数调用过程中使用。虽然它们通常需要支持多个被装饰对象以及多个调用,但是也有许多方法来实现这些目标:实例属性、全局变量、非局部闭包变量和函数属性,全都可以用来保持状态。
例如,这里是文章《系统学习Python——装饰器:函数装饰器-[跟踪调用]》中例子的扩展版本,其中添加了对带有**
语法的关键字参数的支持,并且返回被包装函数的结果,以支持更多的用例:
class tracer:
def __init__(self, func):
self.calls = 0
self.func = func
def __call__(self, *args, **kargs):
self.calls += 1
print('call %s to %s' % (self.calls, self.func.__name__))
self.func(*args, **kargs)
@tracer
def spam(a, b, c):
print(a + b + c)
@tracer
def eggs(x, y):
print(x ** y)
span(1, 2, 3)
span(a=1, b=2, c=3)
eggs(2, 16)
eggs(4, y=4)
就像最初的版本一样,这里的代码使用类实例属性来显式地保存状态。每个实例都有各自的被包装函数和调用计数器的信息一一每次装饰都有自己的副本。当在Python2.X和Python3.X下作为脚本运行的时候,这个版本的输出如下所示。注意spam
和eggs
函数拥有自己的调用计数器,因为每次装饰都创建一个新的类实例:
尽管对于装饰函数有用,但是当这种编程方案在方法上应用的时候仍有问题,在后面的文章中我们将详细阐述这个问题。
参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.