Altre risposte suggerite aggiungendo self
al primo parametro.
Ma solitamente le chiamate di __init__
nelle classi parent sono fatte da super
.
Considerate questo esempio:
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
classe contiene un ordine in cui i costruttori e initializators dovrebbero essere chiamati:
>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
Sede, che prima AB
's __init__
viene invocato, poi B
' s, quindi A
e quindi object
. controllo
Let:
>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A
Ma queste chiamate attraverso questa catena sono fatte da super
. Quando digitiamo super(AB, self)
, significa: trova la classe successiva dopo AB
nella catena __mro__
di self
.
Allora dovremmo invocare super
in B
, cercando la classe successiva nella catena dopo B
: super(B, self)
.
È importante utilizzare super
e non chiamare manualmente A.__init__(self,...)
, ecc., Poiché potrebbe causare problemi in seguito. Read this for more info.
Quindi, se si rimane con super
, c'è un problema. I metodi __init__
nelle tue classi prevedono parametri diversi. E non puoi sapere con certezza l'ordine in cui super
invocherà metodi in queste classi. L'ordine è determinato da C3 algorithm al momento della creazione della classe. Nelle sottoclassi, altre classi possono ottenere tra la catena di chiamate. Pertanto non è possibile avere parametri diversi in __init__
, poiché in questo caso si dovrà sempre considerare tutta la catena di ereditarietà per capire come verranno chiamati i metodi __init__
.
Ad esempio, considerare l'aggiunta di classi C(A)
e D(B)
e di sottoclasse CD
. Quindi A
non verrà più richiamato dopo B
, ma dopo 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
Quindi penso che sia una buona idea pensare di utilizzare delegation
invece di eredità qui.
class AB(object):
def __init__(self, x, y, z=0):
self.a = A(x,y)
self.b = B(z)
Quindi, basta creare a
e b
istanze di A
e B
classi all'interno AB
oggetto. E quindi possono usarli come necessario attraverso i metodi facendo riferimento a self.a
e self.b
.
Per utilizzare o meno la delega dipende dal vostro caso che non è chiaro dalla vostra domanda. Ma potrebbe essere un'opzione da considerare.
Perché usi qui l'ereditarietà anziché la delega? Perché il caso dell'ereditarietà multipla dovrebbe essere gestito usando 'super', che non funzionerà bene a causa dei diversi parametri in' __init__'. – ovgolovin
@ovgolovin Perché sono un programmatore inesperto. Non so cosa sia la delega. Proverò a esaminarlo. –
@ovgolovin Grazie. Si è scoperto che ho risolto il mio problema con un wrapper. –