Discussione:
__init__ ed ereditarietà multipla
(troppo vecchio per rispondere)
bc
2013-02-23 13:55:17 UTC
Permalink
Ho 2 classi distinte che vorrei raggruppare in una terza classe.
Entrambe le classi base hanno un init che vorrei richiamare, ma con il
sistema super(miaclasse,self).__init__() mi richiama solo l'init della
prima (in ordine di inserimento nella lista di ereditarietà) e non ho
trovato una sintassi per fargli richiamare l'altra.
Su google non ho trovato quasi nulla con il caso che cercavo a parte un
vago suggerimento che ho sviluppato nell'esempio riportato piu sotto.

L'esempio Funziona bene e fa quello che mi aspetto, ma ho sempre visto
usare super(...) Volevo sapere se l'invocazione diretta col NOME della
classe genitore è corretta (perché non mi sembra di averlo mai visto)
First.__init__(self, eventuali parametri)
Second.__init__(self, eventuali parametri)

Esempio:
-------------------
class First(object):
def __init__(self, v1):
self.v1=v1
print "first", self.__dict__
print "v1", self.v1


class Second(object):
def __init__(self, v2, v3):
self.v2=v2
self.v3=v3
print "second", self.__dict__
print "v2", self.v2
print "v3", self.v3

class Third(Second, First):
def __init__(self):

Second.__init__(self, 2, 3)
First.__init__(self, 1)

print "third", self.__dict__
print "v1", self.v1
print "v2", self.v2
print "v3", self.v3

---------------------
output:

second {'v2': 2, 'v3': 3}
v2 2
v3 3
first {'v1': 1, 'v2': 2, 'v3': 3}
v1 1
third {'v1': 1, 'v2': 2, 'v3': 3}
v1 1
v2 2
v3 3
Vito De Tullio
2013-02-23 16:55:49 UTC
Permalink
Post by bc
L'esempio Funziona bene e fa quello che mi aspetto, ma ho sempre visto
usare super(...) Volevo sapere se l'invocazione diretta col NOME della
classe genitore è corretta
risposta breve: se hai necessità di chiamare il costruttore di *entrambe* le
classi parent *e* non hai diretto accesso alle classi First e Second,
l'invocazione può anche essere corretta (ci sono modi per wrappare First e
Second, ma sono scomodi), ma se usi super() anche nelle classi First e
Second allora verranno chiamate anch'esse

#!/usr/bin/env python

class First(object):
def __init__(self, v1, **kwargs):
self.v1 = v1
super(First, self).__init__(**kwargs)

class Second(object):
def __init__(self, v2, **kwargs):
self.v2 = v2
super(Second, self).__init__(**kwargs)

class Third(Second, First):
def __init__(self, v3, **kwargs):
self.v3 = v3
super(Third, self).__init__(**kwargs)

if __name__ == '__main__':
t = Third(v1=1, v2=2, v3=3)
print t.__dict__


risposta lunga:

in http://docs.python.org/2/library/functions.html#super è spiegato che
super() è pensato per due usi principali:

* nel caso di ereditarietà singola, evita di usare il nome della classe
parent
* nel caso di ereditarietà "cooperativa", consente di chiamare i metodi
omologhi delle classi parent o "sibling"

in teoria tu vuoi ricadere nel secondo caso: l'idea è che super() non chiama
necessariamente il metodo della classe padre, ma chiama il metodo della
classe successiva nel MRO. se ci sono chiamate super() nelle implementazioni
dei metodi di *tutte* le classi, allora, tutti i metodi saranno chiamati.
Post by bc
Third.__mro__
(<class '__main__.Third'>,
<class '__main__.Second'>,
<class '__main__.First'>,
<type 'object'>)

quindi invocando un qualunque metodo di Third esso sarà cercato prima in
Third stesso, poi in Second, poi in First, poi in object.

nel caso particolare del costruttore

alla costruzione di Third() sarà chiamato

super(Third, self).__init__

cioè il costruttore della classe subito seguente nell'MRO (Second) che
chiamerà

super(Second, self).__init__

cioè il costruttore della classe subito seguente nello stesso MRO (First)
che chiamerà

super(First, self).__init__

cioè il costruttore della classe subito seguente dello stesso MRO (object).


ovviamente se istanzi un oggetto Second, poiché nel suo __mro__ non c'è
First, super(Second, self) punterà direttamente ad object()


l'unico problema che ho con super() è che è una soluzione all-or-nothing:
per funzionare al meglio (nella modalità cooperativa) ogni classe deve
usarlo.
--
ZeD
bc
2013-02-23 17:35:53 UTC
Permalink
Post by Vito De Tullio
ma se usi super() anche nelle classi First e
Second allora verranno chiamate anch'esse
GRAZIE!

Ecco, non avevo capito questa discriminante.
Credevo che fosse inutile chiamare super nelle classi First e Second e
non avevo nemmeno provato. Un poco mi sembra ancora strano visto che in
effetti non ho mai chiamato un super che fa a richiamare l'init (presumo
vuoto) della classe "object".

Comunque le classi fanno parte del codice che sto scrivendo, quindi ho
applicato il tuo consiglio per usare super.

L'altra soluzione mi era sembrata strana, anche se funzionava.

Loading...