分类目录:《系统学习Python》总目录
如果想要函数装饰器在简单函数和类级别的方法上都能工作,最直接的解决办法在于使用前面文章介绍的状态保持方案之一:把自己的函数装饰器编写为嵌套的def
,这样你就不会陷入单一的self
实例参数既是包装器类实例,又是主体类实例了的困境。
如下的替代方案用Python3.X的非局部变量进行了修补;如果要在Python2.X下使用,则可以重新编写它,为可更改的calls
状态变量使用函数属性。由于被装饰的方法重新绑定到了简单函数而不是实例对象,所以Python正确地传递了Person
对象作为第一位参数,并且装饰器将其从*args
中的第一项传递给真正被装饰方法的self
参数:
def tracer(func):
calls = 0
def onCall(*args, **kwargs):
nonlocal calls
calls += 1
print('call %s to %s' % (calls, func.__name__))
return func(*args, **kwargs)
return onCall
if __name__ == '__main__':
@tracer
def spam(a, b, c):
print(a + b + c)
@tracer
def 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 = name
self.pay = pay
@tracer
def giveRaise(self, percent):
self.pay *= (1.0 + percent)
@tracer
def 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.