Вызовите метод родительского класса из дочернего класса в Python? - PullRequest
513 голосов
/ 30 апреля 2009

При создании простой иерархии объектов в Python я хотел бы иметь возможность вызывать методы родительского класса из производного класса. В Perl и Java для этого есть ключевое слово (super). В Perl я мог бы сделать это:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

sub frotz {
   my $str = SUPER::frotz();
   return uc($str);
}

В python кажется, что я должен явно назвать родительский класс от дочернего. В приведенном выше примере мне нужно сделать что-то вроде Foo::frotz().

Это кажется неправильным, поскольку такое поведение затрудняет создание глубоких иерархий. Если дети должны знать, какой класс определяет унаследованный метод, то создается всякая информационная боль.

Это фактическое ограничение в python, пробел в моем понимании или оба?

Ответы [ 15 ]

612 голосов
/ 30 апреля 2009

Да, но только с классами нового стиля . Используйте функцию super():

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)

Для Python 3.x вы можете использовать:

class Foo(Bar):
    def baz(self, arg):
        return super().baz(arg)
128 голосов
/ 30 апреля 2009

Python также имеет супер , а также:

<strong>super</strong>(type[, object-or-type])

Возвращает прокси-объект, который делегирует вызовы метода родительскому или родственному классу типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе. Порядок поиска такой же, как в getattr (), за исключением того, что сам тип пропускается.

Пример:

class A(object):     # deriving from 'object' declares A as a 'new-style-class'
    def foo(self):
        print "foo"

class B(A):
    def foo(self):
        super(B, self).foo()   # calls 'A.foo()'

myB = B()
myB.foo()
78 голосов
/ 30 апреля 2009
ImmediateParentClass.frotz(self)

будет хорошо, независимо от того, определил ли родительский класс frotz сам или унаследовал его. super требуется только для правильной поддержки множественного наследования (и тогда оно работает, только если каждый класс использует его должным образом). В общем, AnyClass.whatever будет искать whatever в предках AnyClass, если AnyClass не определит / не переопределит его, и это верно для "дочернего класса, вызывающего метод родителя", как и для любого другого вхождения !

67 голосов
/ 26 июля 2016

Python 3 имеет другой и более простой синтаксис для вызова родительского метода.

Если Foo класс наследует от Bar, то из Bar.__init__ можно вызвать из Foo через super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)
35 голосов
/ 11 июля 2017

Во многих ответах объясняется, как вызвать метод от родителя, который был переопределен в дочернем элементе.

Однако

«Как вы вызываете метод родительского класса из дочернего класса?»

может также означать:

"Как вы вызываете унаследованные методы?"

Вы можете вызывать методы, унаследованные от родительского класса, так же, как если бы они были методами дочернего класса, если они не были перезаписаны.

например. в питоне 3:

class A():
  def bar(self, string):
    print("Hi, I'm bar, inherited from A"+string)

class B(A):
  def baz(self):
    self.bar(" - called by baz in B")

B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"

Да, это может быть довольно очевидно, но я чувствую, что, не указывая на это, люди могут оставить этот поток с впечатлением, что вы должны перепрыгивать через нелепые обручи, просто чтобы получить доступ к унаследованным методам в python. Тем более, что этот вопрос высоко оценивается при поиске «как получить доступ к методу родительского класса в Python», а OP написан с точки зрения кого-то, кто плохо знаком с python.

Я нашел: https://docs.python.org/3/tutorial/classes.html#inheritance быть полезным для понимания того, как вы получаете доступ к унаследованным методам.

26 голосов
/ 17 апреля 2013

Вот пример использования super () :

#New-style classes inherit from object, or from another new-style class
class Dog(object):

    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self):
        self.moves.append('walk')
        self.moves.append('run')

    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super(Superdog, self).moves_setup()
        self.moves.append('fly')

dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly']. 
#As you can see our Superdog has all moves defined in the base Dog class
13 голосов
/ 30 апреля 2009

В Python тоже есть супер (). Это немного шатко из-за старых и новых стилей Python, но довольно часто используется, например, в конструкторах:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5
9 голосов
/ 31 декабря 2011

Я бы порекомендовал использовать CLASS.__bases__ как то так

class A:
   def __init__(self):
        print "I am Class %s"%self.__class__.__name__
        for parentClass in self.__class__.__bases__:
              print "   I am inherited from:",parentClass.__name__
              #parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
6 голосов
/ 09 декабря 2015

Если вы не знаете, сколько аргументов вы можете получить, и хотите передать их все также ребенку:

class Foo(bar)
    def baz(self, arg, *args, **kwargs):
        # ... Do your thing
        return super(Foo, self).baz(arg, *args, **kwargs)

(From: Python - Самый простой способ переопределить __init__, где после вызова super () должен использоваться дополнительный kwarg? )

4 голосов
/ 10 декабря 2014

В python также есть супер ().

Пример вызова метода суперкласса из метода подкласса

class Dog(object):
    name = ''
    moves = []

    def __init__(self, name):
        self.name = name

    def moves_setup(self,x):
        self.moves.append('walk')
        self.moves.append('run')
        self.moves.append(x)
    def get_moves(self):
        return self.moves

class Superdog(Dog):

    #Let's try to append new fly ability to our Superdog
    def moves_setup(self):
        #Set default moves by calling method of parent class
        super().moves_setup("hello world")
        self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves()) 

Этот пример аналогичен тому, который описан выше. Однако есть одно отличие, заключающееся в том, что super не передает никаких аргументов. Этот код выполняется в версии Python 3.4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...