[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