代码之家  ›  专栏  ›  技术社区  ›  DanielSank

如何将修饰符应用于超类的方法?

  •  3
  • DanielSank  · 技术社区  · 11 年前

    假设我有一个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 应用于继承自 食品 。例如,我的子类可以像

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

    1 回复  |  直到 11 年前
        1
  •  2
  •   abarnert    11 年前

    我假设你 真正地 要做的不是修饰这些方法的基类副本,而是修饰子类中这些方法的新覆盖副本。

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

    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 在每个直接基上,每个基将搜索该共同祖先一次,但调用 获取属性 在新类上只会在最后搜索一次。

    正如user2357112在一条评论中指出的那样,如果你想要覆盖的是“如果我没有覆盖任何东西,会调用什么”,你可以通过构造新类来实现这一点 第一 ,然后通过调用 获取属性 结果类本身。在2.x中,这意味着你必须处理未绑定的方法而不是函数(在3.x中,那不是问题,因为未绑定方法只是 功能),但收益可能大于成本。