[Python] Ereditarietà tra classi: un semplice esempio pratico da chiarire
Daniele Varrazzo
piro a develer.com
Ven 21 Nov 2014 20:41:58 CET
On 2014-11-21 17:53, Marco Ippolito wrote:
> Ciao Daniele,
> ti ringrazio per l'aiuto.
>
> Ho modificato l'esempio, passando tutte le variabili locali (nome,
> cognome, citta) al costruttore di sub. E coś funziona (come vedi
> sotto).
>
> #!/usr/bin/python
>
> class Super:
> def __init__(self, nome, cognome, indirizzo):
> self.nome = nome
> self.cognome = cognome
> self.indirizzo = indirizzo
> self.nome_intero = '%s %s' % (self.nome, self.cognome)
>
> def super_meth_1(self):
> return '%s abita in %s' % (self.nome_intero, self.indirizzo)
>
> def get_super_result(self):
> return self.super_meth_1()
>
> class Sub(Super):
> def __init__(self, nome, cognome, indirizzo, cosa_fa):
> Super.__init__(self, nome, cognome, indirizzo)
> self.cosa_fa = cosa_fa
>
> def sub_meth_1(self):
> return '%s %s' % (self.nome_intero, self.cosa_fa)
>
> def get_sub_meth_1(self):
> return self.sub_meth_1()
>
>
> if __name__ == '__main__':
>
> nome_f = 'Marco'
> cognome_f = 'Ippolito'
> abita_f = 'Milano'
> super_class = Super(nome_f, cognome_f, abita_f)
> ris_super = super_class.get_super_result()
> print "ris_super: ", ris_super
> cosa_f = 'suona'
> sub = Sub(nome_f, cognome_f, abita_f, cosa_f)
> ris_sub_1 = sub.get_sub_meth_1()
> print "ris_sub_1: ", ris_sub_1
> ris_sub_2 = sub.get_super_result()
> print "ris_sub_2: ", ris_sub_2
>
> ./classInheritage.py
> ris_super: Marco Ippolito abita in Milano
> ris_sub_1: Marco Ippolito suona
> ris_sub_2: Marco Ippolito abita in Milano
>
> C'è un modo per passare far ś che nel main passi a Sub solo le
> variabili che lo "differenziano" (specializzano) rispetto a Super?
> Cioè c'è un modo per far ś che io possa passare in "main" solo la
> variabile "cosa_f"?
Nel caso in esempio si fa male. Il pattern migliore e` quello di
elencare gli argomenti.
La cosa comincia ad essere utile se stabilisci che i costruttori delle
tue classi debbano essere chiamati solo con argomenti keyword, ovvero,
se stabilisci che chiamerai
sub = Sub(nome=nome_f, cognome=cognome_f, abita=abita_f,
cosa_fa=cosa_f)
allora puoi usare **kwargs e fare:
class Super:
def __init__(self, nome, cognome, indirizzo):
self.nome = nome
self.cognome = cognome
self.indirizzo = indirizzo
self.nome_intero = '%s %s' % (self.nome, self.cognome)
class Sub(Super):
def __init__(self, cosa_fa, **kwargs):
Super.__init__(self, **kwargs)
self.cosa_fa = cosa_fa
considerando che tipicamente definirai il costruttore solo in un punto
ma lo chiamerai in diversi punti ti conviene essere piu` verboso nelle
definizioni degli __init__ e risparmiare nell'invocazioe, quindi
lasciare le cose come stanno.
Questa non e` l'unica cosa che si potrebbe tenere in considerazione
pero`. Il tuo e` un esempio di studio, che non ha veri vincoli. In casi
piu` reali potresti avere una gerarchia di oggetti dove pochi argomenti
(tipo fino a 3, ma meno sono e meglio e`) andranno *sempre* specificati
per ogni oggetto della gerarchia, mentre ci puo` essere un turbinare di
argomenti che sono a) opzionali e b) specifici solo di certe
sottoclassi. In questo caso il modo migliore (secondo me, YMMV) di
organizzare il codice e` quello di passare gli argomenti fondamentali in
maniera posizionale (potrebbero anche essere passati con keyword,
l'importante e` mantenere la possibilita` di fare entrambe le cose) e
usare **kwargs per tutti gli altri, in modo da ignorare quelli che non
si conoscono ma di propagarli.
Per esempio (non testato, ovviamente):
class Persona(object):
def __init__(self, nome):
self.nome = nome
class Lavoratore(Persona):
def __init__(self, nome, ruolo, salario=None, **kwargs):
super(Lavoratore, self).__init__(nome, **kwargs)
self.ruolo = ruolo
self.salario = salario
class Studente(Persona):
def __init__(self, nome, scuola, classe=None, **kwargs):
super(Studente, self).__init__(nome, **kwargs)
self.scuola = ...
class StudenteUniversitario(Studente):
def __init__(self, nome, fuoricorso_dal=None, **kwargs):
super(StudenteUniversitario, self).__init__(nome, **kwargs)
...
Il nome puoi passarlo con keyword o meno, gli altri argomenti devono
avere una keyword.
p1 = StudenteUniversitario("Tizio Caio", scuola="Anormale",
fuoricorso_dal=1996)
p2 = Lavoratore(nome="Pinco Pallini", ruolo=...)
Avere classi che richiedono un gran numero di parametri posizionali da
passare non e` una buona cosa: e` facile sbagliare nel passaggio. Se gli
argomenti cominciano ad essere tanti e` meglio richiedere che vengano
passati con keyword (ma e` ancora meglio chiedersi come mai ci siano
tanti parametri e cambiare qualcosa nel codice).
-- Daniele
Maggiori informazioni sulla lista
Python