分类目录:《系统学习Python》总目录
如果想要函数装饰器在简单函数和类级别的方法上都能工作,最直接的解决办法在于使用前面文章介绍的状态保持方案之一:把自己的函数装饰器编写为嵌套的def
,这样你就不会陷入单一的self
实例参数既是包装器类实例,又是主体类实例了的困境。
如下的替代方案用Python3.X的非局部变量进行了修补;如果要在Python2.X下使用,则可以重新编写它,为可更改的calls
状态变量使用函数属性。由于被装饰的方法重新绑定到了简单函数而不是实例对象,所以Python正确地传递了Person
对象作为第一位参数,并且装饰器将其从*args
中的第一项传递给真正被装饰方法的self
参数:
def tracer(func):calls = 0def onCall(*args, **kwargs):nonlocal callscalls += 1print('call %s to %s' % (calls, func.__name__))return func(*args, **kwargs)return onCallif __name__ == '__main__':@tracerdef spam(a, b, c):print(a + b + c)@tracerdef eggs(N):print(2 ** N)span(1, 2, 3)span(a=4, b=5, c=6)print(eggs(32))class Person:def __init__(self, name, pay):self.name = nameself.pay = pay@tracerdef giveRaise(self, percent):self.pay *= (1.0 + percent)@tracerdef lastName(self):return self.name.split()[-1]print('methods...')bob = Person('Bob Smith', 50000)sue = Person('Sue Jones', 100000)print(bob.name, sue.name)sue.giveRaise(0.1)print(sue.pay)print(bob.lastName(), sue.lastName())
我们还在一个__name__
测试下缩进了文件的自测试代码,这样装饰器就能够在其他地方导人和使用。这个版本在函数和方法上都有效,但由于其使用了nonlocal
,它只能在Python3.X中运行:
我们可以跟踪运行这些结果,以确保我们能够驾驭这一模型;后面的文章还将提供了它的一个支持类的替代方案,但是更为复杂。
参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.