Aufrufen der Klassenmethode einer Basisklasse in Python

105

Betrachten Sie den folgenden Code:

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

Von Derived.do, wie rufe ich an Base.do?

Normalerweise würde ich superoder sogar den Namen der Basisklasse direkt verwenden, wenn dies eine normale Objektmethode ist, aber anscheinend kann ich keine Möglichkeit finden, die Klassenmethode in der Basisklasse aufzurufen.

Im obigen Beispiel wird eine Klasse anstelle einer Klasse Base.do(a)gedruckt .BaseDerived

Sridhar Ratnakumar
quelle

Antworten:

121

Wenn Sie eine Klasse neuen Stils verwenden (dh von objectPython 2 oder immer von Python 3 abgeleitet), können Sie dies folgendermaßen tun super():

super(Derived, cls).do(a)

Auf diese Weise würden Sie den Code in der Version der Methode der Basisklasse (dh print cls, a) von der abgeleiteten Klasse aufrufen , clsindem Sie ihn auf die abgeleitete Klasse setzen.

David Z.
quelle
8
uh uh .. wie kommt es, dass es mir nie in den Sinn gekommen ist, dass ich es auch superfür Klassenmethoden verwenden kann.
Sridhar Ratnakumar
Dies funktioniert nur (aufgrund einer durch Super auferlegten Einschränkung), wenn die Basis vom Objekt abgeleitet ist, oder? Was machst du, wenn das nicht der Fall ist?
Ars-Longa-Vita-Brevis
Ja, das funktioniert nur für Klassen neuen Stils, die von abgeleitet sind object. (Zumindest in Python 2, aber in Py3 denke ich, dass alle Klassen im neuen Stil sind, IIRC) Andernfalls müssen Sie, glaube Base.do(self, ...)ich, den Namen der Oberklasse hart codieren.
David Z
Innen Derived.do()ist das nicht clsdasselbe wie Derived?
Ray
@ Ray Wenn es sich tatsächlich um eine Instanz Derivedeiner Unterklasse handelt, aber nicht um eine Unterklasse, dann ja.
David Z
15

Das ist eine Weile her, aber ich glaube, ich habe vielleicht eine Antwort gefunden. Wenn Sie eine Methode dekorieren, um eine Klassenmethode zu werden, wird die ursprüngliche ungebundene Methode in einer Eigenschaft namens 'im_func' gespeichert:

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
quelle
2
Hinweis: Dieser Ansatz funktioniert für Klassen im alten Stil, in denen super () nicht funktioniert
Alex Q
2
Auch verfügbar als __func__in Python 2.7 und 3
dtheodor
-3

Das funktioniert bei mir:

Base.do('hi')
Ned Batchelder
quelle
9
Das clsArgument wird dann gebunden werden BasestattDerived
Sridhar Ratnakumar
Was für mich funktioniert, ist Folgendes - das sieht (sehr) nach Neds Antwort aus: Wo sich self von QGraphicsView ableitet, das paintEvent (QPaintEvent) hat. def paintEvent (self, qpntEvent): print dir (self) QGraphicsView.paintEvent (self, qpntEvent)
user192127