Inne odpowiedzi sugerowały dodanie self
do pierwszego parametru.
Ale zwykle wywołania __init__
w klasach nadrzędnych są wykonywane przez super
.
Rozważmy następujący przykład:
class A(object):
def __init__(self, x):
print('__init__ is called in A')
self.x = x
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B, A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
AB
klasa zawiera postanowienie, w którym konstruktorzy i initializators należy nazwie:
>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
See, że pierwszy AB
's __init__
jest wywoływana, następnie B
' s, następnie A
, a następnie object
. check
Miejmy:
>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A
Ale te rozmowy za pośrednictwem tej sieci są wykonane przez super
. Kiedy wpisujemy super(AB, self)
, oznacza to: znajdź następną klasę po AB
w __mro__
łańcuchu self
.
Następnie powinniśmy powołać super
w B
, szukając następnej klasy w łańcuchu po B
: super(B, self)
.
Ważne jest, aby używać super
i nie nawiązywać ręcznie A.__init__(self,...)
itd., Ponieważ może to później prowadzić do problemów. Read this for more info.
Tak więc, jeśli pozostaniesz z super
, to jest problem. __init__
Metody w twoich klasach oczekują różnych parametrów. I nie wiesz na pewno, w jakiej kolejności super
będzie wywoływał metody w tych klasach. Kolejność jest określana przez C3 algorithm w momencie tworzenia klasy. W podklasach inne klasy mogą łączyć się z łańcuchem wywołań. Więc nie można mieć różnych parametrów w __init__
, ponieważ w tym przypadku zawsze będziesz musiał wziąć pod uwagę cały łańcuch dziedziczenia, aby zrozumieć, jak będą wywoływane metody.
Na przykład rozważ dodanie klas podrzędnych C(A)
i D(B)
oraz podklasy CD
. Wtedy A
nie będzie już wywoływany po B
, ale po C
.
class A(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in A')
super(A, self).__init__(*args, **kwargs)
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B,A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
class C(A):
def __init__(self, *args, **kwargs):
print('__init__ is called in C')
super(C, self).__init__(*args, **kwargs)
class D(B):
def __init__(self, *args, **kwargs):
print('__init__ is called in D')
super(D, self).__init__(*args, **kwargs)
class CD(D,C):
def __init__(self, *args, **kwargs):
print('__init__ is called in CD')
super(CD, self).__init__(*args, **kwargs)
class ABCD(CD,AB):
def __init__(self, *args, **kwargs):
print('__init__ is called in ABCD')
super(ABCD, self).__init__(*args, **kwargs)
>>> abcd = ABCD()
__init__ is called in ABCD
__init__ is called in CD
__init__ is called in D
__init__ is called in AB
__init__ is called in B
__init__ is called in C
__init__ is called in A
Więc myślę, że to dobry pomysł, aby myśleć o użyciu delegation
zamiast dziedziczenia tutaj.
class AB(object):
def __init__(self, x, y, z=0):
self.a = A(x,y)
self.b = B(z)
Więc, po prostu stworzyć a
i b
wystąpień A
i B
klas wewnątrz AB
obiektu. A następnie mogą używać ich zgodnie z potrzebami, korzystając z metod, odnosząc się do self.a
i self.b
.
Aby skorzystać lub nie delegacja zależy od przypadku, który nie wynika z Twojego pytania. Ale może to być opcja do rozważenia.
Dlaczego zamiast delegacji używasz dziedziczenia? Ponieważ przypadek wielokrotnego dziedziczenia powinien być obsługiwany za pomocą 'super', który nie będzie działał poprawnie z powodu różnych parametrów w' __init__'. – ovgolovin
@ovgolovin Ponieważ jestem niedoświadczonym programistą. Nie wiem, co to jest delegacja. Spróbuję to przeanalizować. –
@ovgolovin Dzięki. Okazało się, że rozwiązałem swój problem za pomocą opakowania. –