Chiunque armeggi con Python abbastanza a lungo è stato morso (o fatto a pezzi) dal seguente problema:
def foo(a=[]):
a.append(5)
return a
Novizi Python si aspetta questa funzione per restituire sempre una lista con un solo elemento: [5]
. Il risultato è invece molto diverso e molto sorprendente (per un principiante):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
Un mio manager una volta ha avuto il suo primo incontro con questa funzione e l'ha definita "un difetto di progettazione drammatica" del linguaggio. Ho risposto che il comportamento aveva una spiegazione di fondo, ed è davvero molto sconcertante e inaspettato se non capisci gli interni. Tuttavia, non sono stato in grado di rispondere (a me stesso) alla seguente domanda: qual è la ragione per associare l'argomento predefinito alla definizione della funzione e non all'esecuzione della funzione? Dubito che il comportamento sperimentato abbia un uso pratico (chi ha veramente usato variabili statiche in C, senza allevare bug?)
Modifica :
Baczek ha fatto un esempio interessante. Insieme alla maggior parte dei tuoi commenti e di Utaal in particolare, ho approfondito ulteriormente:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
Per me, sembra che la decisione di progettazione sia stata relativa a dove mettere l'ambito dei parametri: all'interno della funzione o "insieme" con essa?
Fare l'associazione all'interno della funzione significherebbe che x
è effettivamente legata all'impostazione predefinita specificata quando la funzione viene chiamata, non definita, qualcosa che presenterebbe un profondo difetto: la def
linea sarebbe "ibrida" nel senso che parte dell'associazione (di l'oggetto funzione) accadrebbe alla definizione e parte (assegnazione dei parametri predefiniti) al momento dell'invocazione della funzione.
Il comportamento effettivo è più coerente: ogni cosa di quella linea viene valutata quando viene eseguita quella linea, cioè alla definizione della funzione.
[5]
" Sono un novizio di Python, e non me lo sarei aspettato, perché ovviamente foo([1])
tornerà [1, 5]
, no [5]
. Quello che intendevi dire è che un principiante si aspetterebbe che la funzione chiamata senza parametro tornerà sempre [5]
.