[Python] Domande varie

Daniele Varrazzo piro a develer.com
Lun 20 Ott 2008 16:47:11 CEST



On Mon, 20 Oct 2008 16:19:20 +0200, "Antonello Mangone"
<antonello.mangone a gmail.com> wrote:
> Gli attributi indicano che stai passando un parametro di tipo tupla

Veramente no: come dizionario. "Come tupla" è con un solo asterisco. Provo
a spiegare meglio a Valerio...

> Il giorno 20 ottobre 2008 15.53, Valerio Pachera <sirio81 a gmail.com> ha
> scritto:
> 
>> Ciao ragazzi, sto leggendo del codice di alcuni programmi e vi sono
>> delle cose che non mi sono chiare.
>>
>> def __init__(self, **kw):
>>  super(Document, self).__init__(**kw)
>>
>> Correggetemi se sbaglio:
>> Qua viene definito il costruttore che richiama il costruttore della
>> classe genitore per estenderlo.
>>
>> Cosa sono gli asterischi????
>> kv ha un significato particolare?

kw è solo un nome (sta per "keywords"), non ha un significato speciale.
Nel corpo del costruttore sarà un dizionario, dove le chiavi saranno i
nomi degli argomenti passati al costruttore, e i valori saranno i valori
degli argomenti. La sintassi non è legata ai soli costruttori, ma a tutte
le funzioni:

    In [24]: def f(**kw): print kw

    In [25]: f(a=10, b=20, c=30)
    {'a': 10, 'c': 30, 'b': 20}

Solo i parametri nominali (passati alla funzione con un nome) vengono messi
nel dizionario delle keyword. Eventuali argomenti posizionali finiscono in
una tupla di argomenti, che può essere usata con la sintassi con un solo
asterisco, quello che intendeva Antonello.

    In [26]: def g(*args, **kw): print args, kw

    In [27]: g(10, 20, foo=30, bar=40)
    (10, 20) {'foo': 30, 'bar': 40}

Tutto questo nella definizione degli argomenti di una funzione. La cosa
"duale" avviene al richiamo di una funzione: se passi una tupla con un
asterisco, questa viene "espansa" coprendo altrettanti argomenti
posizionali

    In [28]: def h(a, b, c):
       ....:     print a, b, c

    In [29]: args = (10, 20, 30)

    In [30]: h(*args)
    10 20 30

mentre un dizionario con due asterischi viene espanso a coprire gli
argomenti nominali:

    In [31]: kwargs = {'a': 11, 'b':12, 'c':13}

    In [32]: h(**kwargs)
    11 12 13

Il costruttore che hai postato come esempio mette insieme le due cose e fa
sì che, al momento di creare un'istanza della sottoclasse, tutti gli
argomenti passati al costruttore vengano trasmessi integralmente al
costruttore della classe di base. E' un pattern che si usa tutte le volte
che si vuole wrappare in modo generico una funzione. Per esempio se voglio
creare una funzione che logga tutti i richiami di altre funzioni:

    In [35]: def call_with_log(f, *args, **kwargs):
       ....:     print "calling", f, args, kwargs
       ....:     return f(*args, **kwargs)

    In [36]: def sum(a, b, carry=0):
        return a+b+carry

    In [38]: call_with_log(sum, 10, 20)
    calling <function sum at 0xc9d578> (10, 20) {}
    Out[38]: 30

    In [39]: call_with_log(sum, 10, 20, carry=1)
    calling <function sum at 0xc9d578> (10, 20) {'carry': 1}
    Out[39]: 31

ho potuto scrivere questa funzione molto generica, in grado di funzionare
con qualunque funzione e qualunque combinazione di argomenti.

-- 
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com


Maggiori informazioni sulla lista Python