[Python] Ereditarietà tra classi: un semplice esempio pratico da chiarire
Marco Ippolito
ippolito.marco a gmail.com
Ven 21 Nov 2014 21:03:11 CET
Mille grazie Daniele delle tue interessanti spiegazioni.
Ammetto che non sapevo che si potesse usare un costrutto del tipo:
class NomeClasse(Super):
def __init__(self, variabili,....., **kwargs):
super(NomeClasse, self).__init__(variab_super, **kwargs)
Hai ragione nel dire che se vengono passati tanti parametri alla
classe, vuol dire che bisogna riguardare il codice, e magari
suddividerlo in più classi.
Marco
Il 21 novembre 2014 20:41, Daniele Varrazzo <piro a develer.com> ha scritto:
> 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 così 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 sì che nel main passi a Sub solo le
>> variabili che lo "differenziano" (specializzano) rispetto a Super?
>> Cioè c'è un modo per far sì 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
>
> _______________________________________________
> Python mailing list
> Python a lists.python.it
> http://lists.python.it/mailman/listinfo/python
Maggiori informazioni sulla lista
Python