Chamando o método de classe de uma classe base em Python

105

Considere o seguinte código:

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

De Derived.do, como faço para ligar Base.do?

Eu normalmente usaria superou mesmo o nome da classe base diretamente se este for um método de objeto normal, mas aparentemente não consigo encontrar uma maneira de chamar o método de classe na classe base.

No exemplo acima, Base.do(a)imprime Baseclasse em vez de Derivedclasse.

Sridhar Ratnakumar
fonte

Respostas:

121

Se você estiver usando uma classe de novo estilo (ou seja, deriva do objectPython 2 ou sempre do Python 3), você pode fazer isso da super()seguinte maneira:

super(Derived, cls).do(a)

É assim que você chamaria o código na versão do método da classe base (ou seja print cls, a), da classe derivada, clssendo definido como a classe derivada.

David Z
fonte
8
uh uh .. como é que nunca me ocorreu que eu também pudesse usar os supermétodos de classe.
Sridhar Ratnakumar
isso só funciona (devido a uma limitação imposta por super) se a base deriva de objeto, certo? o que você faz se não for o caso?
ars-longa-vita-brevis
Sim, isso só funciona para classes de novo estilo, que derivam de object. (pelo menos em Python 2, mas em Py3 eu acho que todas as classes são de novo estilo, IIRC) Caso contrário, você terá que fazer Base.do(self, ...), eu acho, assim codificando permanentemente o nome da superclasse.
David Z de
Por dentro Derived.do(), não é clso mesmo que Derived?
Ray,
@Ray Se for realmente uma instância de, Derivedmas não de uma subclasse, então sim.
David Z,
15

já faz um tempo, mas acho que posso ter encontrado uma resposta. Quando você decora um método para se tornar um método de classe, o método original não associado é armazenado em uma propriedade chamada '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')
Nikolas
fonte
2
Observação: essa abordagem funciona para classes de estilo antigo em que super () não funciona
Alex Q
2
Também disponível como __func__em python 2.7 e 3
dtheodor
-3

Isso funciona para mim:

Base.do('hi')
Ned Batchelder
fonte
9
O clsargumento será então obrigado a Basevez deDerived
Sridhar Ratnakumar
o que funciona para mim é isto - que se parece (muito) com a resposta de Ned: onde self deriva de QGraphicsView que tem paintEvent (QPaintEvent) def paintEvent (self, qpntEvent): print dir (self) QGraphicsView.paintEvent (self, qpntEvent)
usuário192127