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@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a