Вызов метода class базового класса в Python

105

Рассмотрим следующий код:

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)печатает Baseclass вместо Derivedclass.

Шридхар Ратнакумар
источник

Ответы:

121

Если вы используете класс нового стиля (т.е. производный от objectPython 2 или всегда от Python 3), вы можете сделать это super()следующим образом:

super(Derived, cls).do(a)

Вот как вы вызываете код в версии метода (т. Е. print cls, a) Базового класса из производного класса с clsустановкой на производный класс.

Дэвид З
источник
8
эээ .. почему мне никогда не приходило в голову, что я тоже могу использовать superметоды класса.
Шридхар Ратнакумар,
это работает только (из-за ограничения, наложенного super), если база происходит от объекта, верно? что делать, если это не так?
ars-longa-vita-brevis
Да, это работает только для классов нового стиля, производных от object. (по крайней мере, в Python 2, но в Py3 я думаю, что все классы являются новым стилем, IIRC) В противном случае вам Base.do(self, ...), как мне кажется, придется жестко кодировать имя суперкласса.
David Z
Внутри Derived.do()не clsто же самое, что Derived?
Рэй
@Ray Если это на самом деле экземпляр Derivedподкласса, но не подкласса, тогда да.
David Z
15

это было давно, но я думаю, что нашел ответ. Когда вы украшаете метод так, чтобы он стал методом класса, исходный несвязанный метод сохраняется в свойстве с именем 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')
Николас
источник
2
Примечание: этот подход работает для классов старого стиля, где super () не работает
Alex Q
2
Также доступно как __func__в python 2.7 и 3
dtheodor
-3

Это работает для меня:

Base.do('hi')
Нед Батчелдер
источник
9
Тогда clsаргумент будет привязан к BaseвместоDerived
Шридхар Ратнакумар
у меня работает вот это - который выглядит (во многом) как ответ Неда: где self происходит от QGraphicsView, у которого есть paintEvent (QPaintEvent) def paintEvent (self, qpntEvent): print dir (self) QGraphicsView.paintEvent (self, qpntEvent)
user192127