分类目录:《系统学习Python》总目录
前文基于类的代码的微妙之处是,尽管它对于拦截简单函数调用有效,但当它应用于类级别的方法函数的时候,并不是很有效:
def decorator(F):
def __init__(self, func):
self.func = func
def __call__(self, *args):
pass # 使用self.func和*args
class A():
@decorator
def method(self, x, y): # F = decorator(F)
pass
这一点带来的问题是,当装饰器的__call__
方法随后运行的时候,其中的self
接收decorator
类实例,并且类A
的实例不会包含到一个args
中。这使得把调用分派给最初的方法变得不可能,即保持了最初的方法函数的装饰器对象,但是没有实例传递给它。
为了支持函数和方法,嵌套函数这一替代方案将有更好的效果:
def decorator(F):
def wrapper(*args):
return wrapper
@decorator
def func(x, y):
pass
func(1, 1)
class A():
@decorator
def method(self, x, y): # F = decorator(F)
pass
X = A()
X.method(1, 1)
当按照这种方法编写时,wrapper
在其第一个参数里接收了类的实例,因此它可以分发到最初的方法和访问状态信息。
从技术上讲,这种嵌套函数版本是有效的,因为Python创建了一个绑定的方法对象,并且只有当一个方法属性引用简单函数的时候,才把主体类实例传递给该方法的self
参数;当方法引用可调用类的一个实例时,将可调用类的实例传递给self
参数,以允许可调用类访问自己的状态信息。
我们在后续的文章中还将看到这一细微的区别在实际案例中的作用。还需要注意的是,嵌套函数可能是支持函数和方法装饰的最直接方式,但是不一定是唯一方式。例如,之前的文章中提到的描述符,调用的时候接收了描述符和主体类实例。
参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.