Python, nadpisanie dziedziczonej metody klasowej
Mam dwie klasy, Field
i Background
. Wyglądają trochę tak:
class Field( object ):
def __init__( self, a, b ):
self.a = a
self.b = b
self.field = self.buildField()
def buildField( self ):
field = [0,0,0]
return field
class Background( Field ):
def __init__( self, a, b, c ):
super(Background, self).__init__( a, b )
self.field = self.buildField( c )
def buildField( self, c ):
field = [c]
return field
a, b, c = 0, 1, 2
background = Background( a, b, c )
Ten błąd wskazuje na pole buildField()
:
"TypeError: buildField() takes exactly 2 arguments (1 given)."
Oczekiwałem, że Background init () zostanie wywołany jako pierwszy. Aby przekazać "a, b" do pól init(), pole przypisać a i b, a następnie przypisać listę z trzema 0 do pola. Następnie, aby init tła był kontynuowany, aby następnie wywołać własną buildField() i nadpisać self.pole z listą zawierającą c.
It wygląda na to, że nie do końca rozumiem super (), jednak nie byłem w stanie znaleźć rozwiązania mojego problemu po przyjrzeniu się podobnym problemom dziedziczenia w Internecie i wokół tutaj.
Spodziewałem się zachowania takiego jak c++, gdzie klasa może nadpisać metodę, która została odziedziczona. Jak mogę to osiągnąć lub coś podobnego.
Większość problemów, które znalazłem związane z tym były osoby używające podwójnego podkreślenia. Moje doświadczenie z dziedziczeniem z super polega na używaniu odziedziczonej klasy init (), aby po prostu przejść różne zmienne do super klasy. Nic, co wiązałoby się z nadpisywaniem czegokolwiek.
5 answers
Patrząc z perspektywy C++, mogą tu być dwa błędne przekonania.
Po pierwsze, nadpisanie metody z innym podpisem nie przeciąża jej jak w C++. Jeśli jeden z Twoich obiektów tła spróbuje wywołać buildField bez żadnych argumentów, Oryginalna wersja z pola nie zostanie wywołana -- została całkowicie ukryta.
Druga sprawa polega na tym, że jeśli metoda zdefiniowana w superklasie wywoła buildField, to zostanie wywołana wersja podklasy. W Pythonie, wszystkie metody są związane dynamicznie, podobnie jak metoda C++ virtual
.
Field ' s __init__
ma do czynienia z obiektem, którego metoda buildField nie przyjmuje żadnych argumentów. Użyłeś metody z obiektem, który posiada metodę buildField przyjmującą jeden argument.
Rzecz z super
jest taka, że nie zmienia typu obiektu, więc nie powinieneś zmieniać podpisu żadnych metod, które metody klasy nadrzędnej mogą wywoływać.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-07 00:37:49
Jak na razie dobrze.Spodziewałem się wywołania Background INIT (). Aby przekazać "a, b" do pól init (), pole do przypisania a i B
Ah. Tutaj pojawia się błąd.Następnie przypisać listę z trzema 0 ' s w polu.
self.field = self.buildField()
Mimo że linia ta występuje w Field.__init__
, self
jest instancją Background
. więc self.buildField
znajduje Background
metodę buildField
, a nie Field
.
Ponieważ Background.buildField
oczekuje 2 argumentów zamiast 1,
self.field = self.buildField()
Podnosi błąd.
Więc jak powiemy Pythonowi, aby wywołał metodę Field
's buildField
zamiast Background
's?
Celem Wymaganie nazwy (nazwanie atrybutu z podwójnymi podkreślnikami) jest rozwiązanie tego problemu.
class Field(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.field = self.__buildField()
def __buildField(self):
field = [0,0,0]
return field
class Background(Field):
def __init__(self, a, b, c):
super(Background, self).__init__(a, b)
self.field = self.__buildField(c)
def __buildField(self, c):
field = [c]
return field
a, b, c = 0, 1, 2
background = Background(a, b, c)
Nazwa metody __buildField
jest "zniekształcona" do _Field__buildField
wewnątrz Field
więc wewnątrz Field.__init__
,
self.field = self.__buildField()
Wywołania self._Field__buildField()
, czyli Field
' S __buildField
metoda. Podczas gdy podobnie,
self.field = self.__buildField(c)
Inside Background.__init__
calls Background
' s __buildField
metoda.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-15 00:38:15
Oczekiwałem, że wywołanie Background INIT () zostanie wywołane
Właściwie Background init()
jest wywoływany..
class Background( Field ):
def __init__( self, a, b, c ):
super(Background, self).__init__( a, b )
self.field = self.buildField( c )
Zatem pierwsze twierdzenie {[3] } jest wywołaniem metody init super class(Field)
.. i podanie self
jako argumentu.. Teraz to {[5] } jest w rzeczywistości odniesieniem Background class
..
Teraz na zajęciach terenowych: -
class Field( object ):
def __init__( self, a, b ):
print self.__class__ // Prints `<class '__main__.Background'>`
self.a = a
self.b = b
self.field = self.buildField()
Twoja metoda buildField()
faktycznie wywołuje tę W Tle klasy.. Jest to spowodowane tym, że self
jest instancją klasy Background
(spróbuj wydrukować self.__class__
w swojej metodzie __init__
z Field class
).. Gdy minąłeś ją podczas wywoływania metody __init__
, z klasy Background
..
Dlatego dostajesz błąd..
Błąd " TypeError: buildField () pobiera dokładnie 2 argumenty (1 given).
Ponieważ nie przekazujesz żadnej wartości.. Tak więc jedyną przekazaną wartością jest implicit self
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-07 00:24:45
super(Background, self).__init__( a, b )
wywoła:
def __init__( self, a, b ):
self.a = a
self.b = b
self.field = self.buildField()
W Field
. Jednakże self
odnosi się tutaj do instancji background
, a self.buildField()
w rzeczywistości wywołuje buildField()
z Background
, dlatego pojawia się ten błąd.
Wydaje się, że Twój kod powinien być lepiej napisany jako:
class Field( object ):
def __init__( self, a, b ):
self.a = a
self.b = b
self.field = Field.buildField()
@classmethod
def buildField(cls):
field = [0,0,0]
return field
class Background( Field ):
def __init__( self, a, b, c ):
super(Background, self).__init__(a, b)
self.field = Background.buildField(c)
@classmethod
def buildField(cls,c):
field = [c]
return field
a, b, c = 0, 1, 2
background = Background( a, b, c )
Jeśli nie możesz pozwolić konstruktorowi bazowemu na ukończenie, oznacza to, że projekt jest wadliwy.
Dlatego o wiele lepiej jest oddzielić buildField()
należeć do klasy używając classmethod
dekorator lub staticmethod
, jeśli musisz wywołać te metody w swoim konstruktorze.
Jednakże, jeśli konstruktor klasy bazowej nie wywoła żadnej metody instancji z wewnątrz, możesz bezpiecznie zastąpić dowolną metodę tej klasy bazowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-07 00:54:40
Overriding
mówi się o tym, ale to brzmi jak dla mnie chaining constructors or (methods)
A także brzmi jak nadpisanie właściwości:
Pozwól mi wyjaśnić:
Właściwość o nazwie pole {[12] } zostanie zainicjalizowana jako
[0,0,0]
.@property
dekoratorzy wyglądają lepiej.Następnie
Background
klasa nadpisuje tę właściwość.
Szybkie i brudne rozwiązanie
Nie znam Twojej logiki biznesowej, ale czasami mijając super metoda klasy __init__
dała mi większą kontrolę:
#!/usr/bin/env python
class Field( object ):
def __init__( self, a, b ):
self.a = a
self.b = b
self.field = self.buildField()
def buildField( self ):
field = [0,0,0]
return field
class Background( Field ):
def __init__( self, a, b, c ):
# super(Background, self).__init__( a, b )
# Unfortunately you should repeat or move initializing a and b
# properties here
self.a = a
self.b = b
self.field = self.buildField( c )
def buildField( self, c ):
# You can access super class methods
assert super(Background, self).buildField() == [0,0,0]
field = [c]
return field
a, b, c = 0, 1, 2
bg = Background(a,b,c)
assert bg.field == [2]
Używanie właściwości
Ma bardziej czystą składnię.
#!/usr/bin/env python
class Field( object ):
@property
def field(self):
return [0,0,0]
def __init__( self, a, b ):
self.a = a
self.b = b
class Background( Field ):
def __init__( self, a, b, c ):
super(Background, self).__init__( a, b )
self.c = c
assert (self.a, self.b, self.c) == (0,1,2) # We assigned a and b in
# super class's __init__ method
assert super(Background, self).field == [0,0,0]
assert self.field == [2]
@property
def field(self):
return [self.c]
a, b, c = 0, 1, 2
background = Background( a, b, c )
print background.field
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-27 12:58:46