[英]How do I apply decorators to a superclass's methods?
假设我有一个python类
class Foo(object):
def method1(self, x):
print("method1 called with %s" %(x,))
def method2(self, x):
print("method2 called with %s" %(x,))
和一个装饰
def myDecorator(func):
newFunc = someModificationOf(func)
return newFunc
我希望能够子类化Foo
并且在子类定义中以某种方式表明我希望myDecorator
应用于从Foo
继承的方法的某个子集。 例如,我的子类可能喜欢
class Baz(Foo):
methodsToDecorate = ['method2']
这可能吗?
我尝试了什么:
我以为我可以用元类做到这一点:
class Baz(Foo):
__metaclass__ = Meta
methodsToDecorate = ['method2']
class Meta(type):
def __new__(cls, name, bases, d):
for m in d['methodsToDecorate']:
d[m] = myDecorator(d[m])
return type(name, bases, d)
但是,它不起作用,因为'method2'
不在字典中传递给元类的__new__
方法,所以我们得到一个KeyError
。 我喜欢使用元类的想法,因为它允许装饰器操作函数而不是方法,这似乎是一个很好的简化。
我假设你真正想做的不是装饰基类的那些方法的副本,而是装饰子类中这些方法的新重写副本。
如果是这样,那很容易。 传递给元类的字典中不存在这些方法,因为它们没有在类定义中定义,它们是从基类继承的。 哪个元类也可以访问。 所以:
def __new__(cls, name, bases, d):
def find_method(m):
for base in bases:
try:
return getattr(base, m)
except AttributeError:
pass
raise AttributeError("No bases have method '{}'".format(m))
for m in d['methodsToDecorate']:
d[m] = myDecorator(find_method(m))
return type(name, bases, d)
如果你确实想要进入基类并替换它的方法,你当然可以使用相同的技巧。 只是找到方法一起返回基地,这样你就可以setattr
它。
您要求覆盖基类中的方法。 但是,如果该方法实际上来自更远的祖先呢? 然后这仍然有效...但它可能无法按您想要的方式工作。 如果您有多个共享共同祖先的基础,则在每个直接基础上调用getattr
在每个基础上搜索该共同祖先一次,但在新类上调用getattr
将仅在最后搜索一次。
正如user2357112在注释中指出的那样,如果你要覆盖的是“如果我没有覆盖任何东西就会被调用的东西”,你可以先构建新类,然后通过调用后修改它来做到这一点。结果类本身的getattr
。 在2.x中,这是否意味着你必须处理与非绑定方法,而不是功能(在3.x中,这不是一个问题,因为非绑定方法仅仅是函数),但收益可能大于成本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.