如何将decorator应用于超类的方法?

2024-09-28 17:24:30 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个python类

class Foo(object):
    def method1(self, x):
        print("method1 called with %s" %(x,))

    def method2(self, x):
        print("method2 called with %s" %(x,))

还有一个装修工

^{pr2}$

我希望能够将Foo子类化,并且在子类定义中,我希望myDecorator应用于从{}继承的方法的某些子集。例如,我的子类可以像

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。我喜欢使用元类的想法,因为它允许装饰者操作函数,而不是方法,这看起来是一个很好的简化。在


Tags: 方法selffoodefwithbaz子类meta
1条回答
网友
1楼 · 发布于 2024-09-28 17:24:30

我假设您真正想要做的不是修饰基类的那些方法的副本,而是在子类中装饰这些方法的新的重写副本。在

如果是这样,那就很容易了。方法在传递给元类的字典中不存在,因为它们不是在类定义中定义的,而是从基继承的。元类也可以访问。所以:

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)

如果您真的想访问基类并替换它的方法,当然可以使用相同的技巧。只需返回base和found方法,这样就可以setattr它。在


您请求重写基类中的方法。但是如果这个方法真的来自一个更遥远的祖先呢?那么这仍然有效…但它可能无法按你想要的方式工作。如果有多个基共享一个共同的祖先,那么在每个直接基上调用getattr将在每个基上搜索该共同祖先一次,但在新类上调用getattr只会在最后搜索一次。在

正如user2357112在一条注释中指出的,如果您想要重写的是“如果我没有重写任何内容,将会调用什么”,那么您可以先构造新类,然后在事实发生后修改它,方法是在result类本身上调用getattr。在2.x中,这意味着您必须处理未绑定的方法而不是函数(在3.x中,这不是问题,因为未绑定的方法只是函数),但好处可能大于成本。在

相关问题 更多 >