我们希望检查或者改写一部分类的定义,以此来修改类的行为,但是不想通过继承或者元类的方式来做。
如果希望解决这个问题,那么类装饰器绝对是首选。
下面这个示例演示了如何使用类装饰器来重写__getattribute__特殊方法,并为它增加了日志功能:
from functools import wraps
def log_getattribute(cls):
#获取原始的实现方法
orig_getattribute = cls.__getattribute__
#定义新的实现方法,记得要返回原始的实现方法
def new_getattribute(self,name):
print("getting:",name)
return orig_getattribute(self,name)
#修改方法映射并返回
cls.__getattribute__ = new_getattribute
return cls
@log_getattribute
class A:
def __init__(self,x):
self.x = x
如果尝试使用该方法来访问类实例的属性,会得到以下结果:
>>> a=A(12)
>>> a.x
getting: x
12
>>> a.spam()
getting: spam
类装饰器往往是作为混合类或元类等高级技术的替代方案,对于本文中的问题,我们还有一种方法是使用继承来解决:
class LoggedGetattribute:
def __getattribute__(self, name):
print("getting:",name)
return super().__getattribute__(name)
class A(LoggedGetattribute):
def __init__(self,x):
self.x = x
def spam(self):
pass
这么做也是可行的,这样在父类中使用super()需要涉及到方法解析顺序(MRO)、super()以及其他和继承相关的知识。
从某些角度上来看,使用类装饰器显得更加直观一些,而且不会在继承体系中引入新的依赖关系。而且事实证明,因为不使用super()函数,所以运行速度也会更加快。
每天更新Java、python学习资料、技术干货。分享见解,共同成长。
关注公众号,免费获取众多电子版经典教材。