Python Language Definizione di una funzione con argomenti mutabili opzionali


Esempio

C'è un problema quando si usano argomenti opzionali con un tipo predefinito mutabile (descritto in Definire una funzione con argomenti facoltativi ), che può potenzialmente portare a comportamenti imprevisti.

Spiegazione

Questo problema si verifica perché gli argomenti predefiniti di una funzione vengono inizializzati una volta , nel momento in cui viene definita la funzione, e non (come molti altri linguaggi) quando viene chiamata la funzione. I valori predefiniti sono memorizzati nella variabile membro __defaults__ dell'oggetto della __defaults__ .

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Out: (42, [])

Per i tipi immutabili (vedere passaggio degli argomenti e mutabilità ) questo non è un problema perché non c'è modo di mutare la variabile; può essere riassegnato solo sempre, lasciando invariato il valore originale. Quindi, successivamente è garantito avere lo stesso valore di default. Tuttavia, per un tipo mutabile , il valore originale può essere mutato, effettuando chiamate alle sue varie funzioni membro. Di conseguenza, non è garantito che le chiamate successive alla funzione abbiano il valore predefinito iniziale.

def append(elem, to=[]):
    to.append(elem)      # This call to append() mutates the default variable "to"
    return to

append(1)
# Out: [1]

append(2)  # Appends it to the internally stored list
# Out: [1, 2]

append(3, [])  # Using a new created list gives the expected result
# Out: [3]

# Calling it again without argument will append to the internally stored list again
append(4)   
# Out: [1, 2, 4]

Nota: alcuni IDE come PyCharm emetteranno un avviso quando un tipo mutabile viene specificato come attributo predefinito.

Soluzione

Se si desidera assicurarsi che l'argomento predefinito sia sempre quello specificato nella definizione della funzione, la soluzione deve sempre utilizzare un tipo immutabile come argomento predefinito.

Un idioma comune per ottenere ciò quando è necessario un tipo mutabile come predefinito è utilizzare None (immutable) come argomento predefinito e quindi assegnare il valore predefinito effettivo alla variabile argomento se è uguale a None .

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to