Wywołać metodę klasy nadrzędnej z klasy podrzędnej?

606

Podczas tworzenia prostej hierarchii obiektów w Pythonie chciałbym móc wywoływać metody klasy nadrzędnej z klasy pochodnej. W Perlu i Javie istnieje słowo kluczowe dla tego ( super). W Perlu mogę to zrobić:

package Foo;

sub frotz {
    return "Bamf";
}

package Bar;
@ISA = qw(Foo);

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

W Pythonie wydaje się, że muszę wyraźnie nazwać klasę nadrzędną od dziecka. W powyższym przykładzie musiałbym zrobić coś takiego Foo::frotz().

Nie wydaje się to właściwe, ponieważ takie zachowanie utrudnia tworzenie głębokich hierarchii. Jeśli dzieci muszą wiedzieć, która klasa zdefiniowała odziedziczoną metodę, powstają różnego rodzaju bóle informacyjne.

Czy to rzeczywiste ograniczenie w pythonie, luka w moim rozumieniu, czy jedno i drugie?

jjohn
źródło
3
Myślę, że nazywanie klasy rodzicielskiej nie jest takim złym pomysłem. Może to pomóc, gdy klasa potomna dziedziczy od więcej niż jednego rodzica, ponieważ wyraźnie nadajesz jej nazwę.
7
Chociaż opcja nazwania klasy nie jest złym pomysłem, na pewno jest to konieczne.
johndodo
Pamiętaj o zmianach w super obsłudze między Pythonem 2 i Pythonem 3 https://www.python.org/dev/peps/pep-3135/ . Nazywanie klasy nie jest już wymagane (chociaż może wciąż być pomysłem boga, przynajmniej czasami).
jwpfox

Odpowiedzi:

735

Tak, ale tylko z klasami w nowym stylu . Użyj super()funkcji:

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

W przypadku python <3 użyj:

class Foo(Bar):
    def baz(self, arg):
        return super(Foo, self).baz(arg)
Adam Rosenfield
źródło
53
Czy nie można również zrobić „return Bar.baz (self, arg)”? Jeśli tak, co byłoby lepsze?
15
Tak, możesz, ale OP pytał, jak to zrobić bez wyraźnego nazewnictwa nadklasy na stronie wywoływania (w tym przypadku Bar).
Adam Rosenfield
7
super () jest dziwne z wielokrotnym dziedziczeniem. Wzywa do „następnej” klasy. Może to być klasa nadrzędna lub może to być jakaś zupełnie niezwiązana klasa, która pojawia się w innym miejscu w hierarchii.
Steve Jessop
6
Używam języka Python 2.x i pojawia się komunikat „Błąd: musi być typem, a nie classobj”, kiedy to robię
Chris F,
28
Czy składnia super(Foo, self)jest zgodna z Python 2.x? W Pythonie 3.x super()preferowana jest poprawna?
Trevor Boyd Smith
143

Python ma również super :

super(type[, object-or-type])

Zwraca obiekt proxy, który deleguje wywołania metod do nadrzędnej lub siostrzanej klasy typu. Jest to przydatne do uzyskiwania dostępu do odziedziczonych metod, które zostały zastąpione w klasie. Kolejność wyszukiwania jest taka sama, jak używana przez getattr (), tyle że sam typ jest pomijany.

Przykład:

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()
Sójka
źródło
7
Lepszy przykład niż Adam, ponieważ zademonstrowałeś klasę nowego stylu z klasą bazową obiektu. Brakuje tylko linku do zajęć w nowym stylu.
Samuel
82
ImmediateParentClass.frotz(self)

będzie dobrze, bez względu na to, czy bezpośrednia klasa nadrzędna zdefiniowała frotzsię, czy odziedziczyła. superjest potrzebny tylko do prawidłowej obsługi wielokrotnego dziedziczenia (a wtedy działa tylko wtedy, gdy każda klasa używa go poprawnie). Ogólnie rzecz biorąc, AnyClass.whateverbędzie patrzeć whateverw AnyClass„s przodków jeśli AnyClassnie definiuje / nadpisać go, a to odnosi się do«klasy dziecięcej wywołanie metody rodzica», jak dla każdego innego wystąpienia!

Alex Martelli
źródło
Wymaga to, aby ImmediateParentClass również był obecny w zakresie, w którym to polecenie może zostać wykonane. Samo importowanie obiektu z modułu nie pomoże.
Tushar Vazirani
co jeśli jest to metoda klasowa?
Shiplu Mokaddim,
@TusharVazirani, jeśli klasa rodzicielska jest natychmiastowa parent, to należy do całej klasy, prawda?
Yaroslav Nikitenko
1
@YaroslavNikitenko Mówię o importowaniu instancji, a nie klasy.
Tushar Vazirani
1
@TusharVazirani teraz rozumiem, dziękuję. Myślałem o wywołaniu z metody obecnej klasy (jak stwierdził OP).
Jarosław Nikitenko
74

Python 3 ma inną i prostszą składnię do wywoływania metody nadrzędnej.

Jeśli Fooklasa dziedziczy po Bar, to Bar.__init__można wywołać z from Fooza pośrednictwem super().__init__():

class Foo(Bar):

    def __init__(self, *args, **kwargs):
        # invoke Bar.__init__
        super().__init__(*args, **kwargs)
Arun Ghosh
źródło
5
Dobrze słyszeć, że python 3 ma lepsze rozwiązanie. Pytanie pochodzi od Pythona 2.X. Dziękuję za sugestię.
jjohn
45

Wiele odpowiedzi wyjaśniło, jak wywołać metodę nadrzędną, która została zastąpiona przez dziecko.

jednak

„jak wywołać metodę klasy nadrzędnej z klasy podrzędnej?”

może również oznaczać:

„jak nazywacie metody dziedziczone?”

Możesz wywoływać metody dziedziczone z klasy nadrzędnej tak, jakby były metodami klasy podrzędnej, o ile nie zostały zastąpione.

np. w python 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"

tak, może to być dość oczywiste, ale czuję, że bez wskazania tego, ludzie mogą zostawić ten wątek z wrażeniem, że musisz skakać przez absurdalne obręcze tylko po to, aby uzyskać dostęp do odziedziczonych metod w pythonie. Zwłaszcza, że ​​to pytanie jest bardzo cenne w wyszukiwaniu „jak uzyskać dostęp do metody klasy nadrzędnej w Pythonie”, a OP jest napisane z perspektywy kogoś nowego w Pythonie.

Uważam, że: https://docs.python.org/3/tutorial/classes.html#inheritance jest przydatny w zrozumieniu, w jaki sposób uzyskujesz dostęp do odziedziczonych metod.

Ben
źródło
@gizzmole w jakiej sytuacji to nie działa? Z przyjemnością dodam wszelkie zastrzeżenia lub ostrzeżenia, które są istotne, ale nie mogłem zrozumieć, w jaki sposób zamieszczony link był istotny dla tej odpowiedzi.
Ben
@Ben Niestety nie przeczytałem twojej odpowiedzi wystarczająco uważnie. Ta odpowiedź nie odpowiada na pytanie, jak przeciążać funkcje, ale odpowiada na inne pytanie. Usunąłem swój początkowy komentarz.
gizzmole
@gizzmole ah, nie martw się. Zdaję sobie sprawę, że ta odpowiedź nie dotyczy funkcji przeciążania, jednak pytanie nie mówi wprost o przeciążeniu (chociaż podany przykład perla pokazuje przypadek przeciążenia). Zdecydowana większość innych odpowiedzi dotyczy przeciążenia - ta odpowiedź jest przeznaczona dla osób, które jej nie potrzebują.
Ben,
@Ben, co jeśli chcę wywołać B (). Baz () z innej klasy o nazwie „C” przy użyciu zmiennych zdefiniowanych w C ?. Próbowałem wykonać B (). Baz () w klasie C, gdzie self.string to kolejna wartość. Nic mi nie dało, kiedy wykonałem egzekucję
joey
@joey Nie jestem pewien, co próbujesz zrobić lub czy jest to objęte zakresem tego pytania. Łańcuch jest zmienną lokalną - ustawienie self.stringnic nie da. W klasie C można jednak jeszcze zadzwonićB().bar(string)
Ben
26

Oto przykład użycia 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
tak
źródło
Czy to nie zły przykład? Uważam, że używanie Super nie jest bezpieczne, chyba że cała twoja hierarchia jest klasami „nowego stylu” i poprawnie wywołuje Super ().
Init
13

W Pythonie jest też super (). Jest nieco nieporadny z powodu klas starego i nowego stylu Pythona, ale jest dość powszechnie stosowany np. W konstruktorach:

class Foo(Bar):
    def __init__(self):
        super(Foo, self).__init__()
        self.baz = 5
Lawrence
źródło
9

Poleciłbym użycie CLASS.__bases__ czegoś takiego

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()
Joran Beasley
źródło
1
Pamiętaj, że jak można stwierdzić na podstawie wielu odniesień do super tutaj, ludzie naprawdę nie lubią używać baz, chyba że robisz coś naprawdę głębokiego. Jeśli nie lubisz super , spójrz na mro . Pierwsze wejście w mro jest bezpieczniejsze niż śledzenie, którego wejścia w bazach użyć. Wielokrotne dziedziczenie w Pythonie skanuje pewne rzeczy do tyłu, a inne do przodu, więc pozwolenie językowi na odwrócenie procesu jest najbezpieczniejsze.
Jon Jay Obermark,
4

W pythonie znajduje się również super ().

Przykład wywołania metody superklasy z metody podklasy

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()) 

Ten przykład jest podobny do tego wyjaśnionego powyżej, jednak istnieje jedna różnica polegająca na tym, że super nie ma żadnych argumentów. Powyższy kod jest wykonywalny w wersji Python 3.4.

kkk
źródło
2

W tym przykładzie cafec_paramjest to klasa podstawowa (klasa nadrzędna) i abcklasa podrzędna. abcwywołuje AWCmetodę w klasie bazowej.

class cafec_param:

    def __init__(self,precip,pe,awc,nmonths):

        self.precip = precip
        self.pe = pe
        self.awc = awc
        self.nmonths = nmonths

    def AWC(self):

        if self.awc<254:
            Ss = self.awc
            Su = 0
            self.Ss=Ss
        else:
            Ss = 254; Su = self.awc-254
            self.Ss=Ss + Su   
        AWC = Ss + Su
        return self.Ss


    def test(self):
        return self.Ss
        #return self.Ss*4

class abc(cafec_param):
    def rr(self):
        return self.AWC()


ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())

Wynik

56

56

56
Chan
źródło
1

W Pythonie 2 nie miałem dużo szczęścia z super (). Użyłem odpowiedzi z jimifiki w tym wątku SO, jak odwoływać się do metody nadrzędnej w pythonie? . Następnie dodałem do tego swój własny mały zwrot, który moim zdaniem poprawia użyteczność (szczególnie jeśli masz długie nazwy klas).

Zdefiniuj klasę podstawową w jednym module:

 # myA.py

class A():     
    def foo( self ):
        print "foo"

Następnie zaimportuj klasę do innych modułów as parent:

# myB.py

from myA import A as parent

class B( parent ):
    def foo( self ):
        parent.foo( self )   # calls 'A.foo()'
BuvinJ
źródło
2
Musisz użyć class A(object): zamiast class A(): wtedy super () zadziała
blndev 17.09.17
Nie jestem pewien, czy podążam. Czy masz na myśli definicję klasy? Oczywiście, musisz wskazać, że klasa ma rodzica, aby pomyśleć, że możesz odnieść się do rodzica! Ponieważ opublikowałem to 9 miesięcy temu, jestem trochę niejasny w szczegółach, ale myślę, że miałem na myśli przykłady z Arun Ghosh, Lawrence, KKK itp. Nie mają zastosowania w Py 2.x. Zamiast tego oto metoda, która działa i łatwy sposób na odniesienie się do rodzica, dzięki czemu jest nieco bardziej jasne, co robisz. (jak używanie super)
BuvinJ
-1
class department:
    campus_name="attock"
    def printer(self):
        print(self.campus_name)

class CS_dept(department):
    def overr_CS(self):
        department.printer(self)
        print("i am child class1")

c=CS_dept()
c.overr_CS()
maryam mehboob
źródło
-4
class a(object):
    def my_hello(self):
        print "hello ravi"

class b(a):
    def my_hello(self):
    super(b,self).my_hello()
    print "hi"

obj = b()
obj.my_hello()
RAVIKUMAR RACHA
źródło
2
Witamy w Stackoverflow. Odpowiedź na to pytanie została już szczegółowo udzielona prawie dziesięć lat temu, odpowiedź została zaakceptowana i w dużej mierze poparta, a twoja odpowiedź nie dodaje nic nowego. Zamiast tego możesz spróbować odpowiedzieć na nowsze (i najlepiej bez odpowiedzi) pytania. Na marginesie, w edytorze znajduje się przycisk umożliwiający zastosowanie odpowiedniego formatowania kodu.
bruno desthuilliers
-24

To jest bardziej abstrakcyjna metoda:

super(self.__class__,self).baz(arg)
użytkownik806071
źródło
15
self .__ class__ nie działa poprawnie z super, ponieważ self jest zawsze instancją, a jej klasa jest zawsze klasą instancji. Oznacza to, że jeśli użyjesz super (self .__ class__ .. w klasie i ta klasa zostanie odziedziczona, nie będzie już działać.
xitrium
16
Dla podkreślenia, NIE UŻYWAJ TEGO KODU. Pokonuje cały cel super (), którym jest poprawne przejście MRO.
Eevee
1
stackoverflow.com/a/19257335/419348 powiedział, dlaczego nie zadzwonić super(self.__class__, self).baz(arg).
AechoLiu,