【问题标题】:Calling a base class's classmethod in Python在 Python 中调用基类的类方法
【发布时间】:2010-11-19 03:30:15
【问题描述】:

考虑以下代码:

class Base(object):

    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do(a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

> $ python play.py  
> In derived! 
> <class '__main__.Base'> msg

来自Derived.do,我如何呼叫Base.do

如果这是一个普通的对象方法,我通常会直接使用super 甚至基类名称,但显然我找不到在基类中调用类方法的方法。

在上面的示例中,Base.do(a) 打印 Base 类而不是 Derived 类。

【问题讨论】:

标签: python class overriding class-method


【解决方案1】:

如果您使用的是新式类(即从 Python 2 中的 object 派生,或者始终在 Python 3 中派生),您可以使用 super() 像这样:

super(Derived, cls).do(a)

这就是您如何从派生类调用基类版本的方法(即print cls, a)中的代码,并将cls 设置为派生类。

【讨论】:

  • 呃呃..我怎么从来没有想到我也可以在 classmethods 上使用super
  • 这只有在基础派生自对象时才有效(由于 super 施加的限制),对吧?如果不是这样,你会怎么做?
  • 是的,这仅适用于派生自object 的新型类。 (至少在 Python 2 中,但在 Py3 中,我认为所有类都是新样式的 IIRC)否则我认为您必须执行 Base.do(self, ...),从而硬编码超类的名称。
  • Derived.do()里面,clsDerived不一样吗?
  • @Ray 如果它实际上是Derived 的实例,但不是子类,那么是的。
【解决方案2】:

这对我有用:

Base.do('hi')

【讨论】:

  • cls 参数将被绑定到 Base 而不是 Derived
  • 对我有用的是这个 - 看起来(很)像 Ned 的回答: where self 从 QGraphicsView 派生,它有 paintEvent(QPaintEvent) def paintEvent (self, qpntEvent): print dir(self) QGraphicsView .paintEvent(self, qpntEvent)
【解决方案3】:

这已经有一段时间了,但我想我可能已经找到了答案。当你装饰一个方法成为一个类方法时,原始的未绑定方法存储在一个名为“im_func”的属性中:

class Base(object):
    @classmethod
    def do(cls, a):
        print cls, a

class Derived(Base):

    @classmethod
    def do(cls, a):
        print 'In derived!'
        # Base.do(cls, a) -- can't pass `cls`
        Base.do.im_func(cls, a)

if __name__ == '__main__':
    d = Derived()
    d.do('hello')

【讨论】:

  • 注意:这种方法适用于 super() 不起作用的老式类
  • 在 python 2.7 和 3 中也可以作为 __func__ 使用
【解决方案4】:

基于@David Z 的答案,使用:

super(Derived, cls).do(a)

可以进一步简化为:

super(cls, cls).do(a)

我经常使用类方法来提供替代方法来构造我的对象。在下面的示例中,我使用上面的超级函数加载类方法来改变对象的创建方式:

class Base():
    
    def __init__(self,a):
        self.a = a
    
    @classmethod
    def load(cls,a):
        return cls(a=a)
    
class SubBase(Base): 

    @classmethod
    def load(cls,b):
        a = b-1
        return super(cls,cls).load(a=a)
    
base = Base.load(a=1)
print(base)
print(base.a)

sub = SubBase.load(b=3)
print(sub)
print(sub.a)

输出:

<__main__.Base object at 0x128E48B0>
1
<__main__.SubBase object at 0x128E4710>
2

【讨论】:

  • super(cls, cls).do(a) 替换super(Derived, cls).do(a) 不是一个好方法。当您有另一个没有定义load() 方法的class SubSubBase(SubBase) 并且您将尝试使用它时,它将不起作用(实际上会导致异常)。
  • @MartinGrůber:那么 Python3 中的正确方法是什么?只需 super().load(...) 就可以在类方法中正常工作?
  • @MestreLion 不知道什么是正确的方法,但我会继续使用super(Derived, cls).do(a),它适用于 AFAIK。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 2012-05-11
  • 2021-07-18
  • 1970-01-01
  • 2014-09-05
  • 2021-05-13
  • 2014-06-30
相关资源
最近更新 更多