Argomenti di default mutabili

Quando si combinano argomenti mutabili con argomenti di default in Python, può capitare di ottenere risultati inaspettati.
Facciamo un esempio semplice per chiarire il concetto. Immagina di essere un insegnante e di voler creare una funzione per registrare i punteggi degli studenti in diversi compiti. Desideri utilizzare una list per tenere traccia di questi punteggi. Potresti inizialmente scrivere qualcosa del genere:
def record_score(new_score, score_list=[]):
    score_list.append(new_score)
    return score_list

print(record_score(95))  # [95]
print(record_score(85))  # [95, 85]
Sembra che tutto funzioni correttamente. La funzione recordscore riceve un punteggio e una list. Se non viene fornita nessuna list, ne utilizza una vuota (quella definita come scorelist=[]).
Quando chiami recordscore(95), sembra che la funzione funzioni regolarmente: restituisce una list con il punteggio 95. Ma se subito dopo chiami recordscore(85), la funzione restituisce una list con entrambi i punteggi 95 e 85, come se si ricordasse la list usata in precedenza.
Questo potrebbe lasciarti perplesso. Nella maggior parte dei linguaggi di programmazione, quando una funzione termina, tutte le sue variabili locali (come score_list) vengono eliminate e dimenticate. La volta successiva in cui la funzione viene chiamata, riparte da zero.
In Python, tuttavia, il comportamento è diverso quando un oggetto mutabile viene usato come argomento di default. Python crea l'argomento di default una sola volta, nel momento in cui la funzione viene definita. Ogni volta che si chiama record_score senza specificare una list, Python utilizza la stessa list creata la prima volta. Se modifichi quella list (ad esempio aggiungendo un punteggio), la modifica persisterà anche alla chiamata successiva della funzione.
Di conseguenza, nella nostra funzione, score_list viene condivisa tra tutte le chiamate in cui non forniamo una list personalizzata. Ecco perché i punteggi si accumulano nel nostro esempio.
Questo non era ciò che volevamo! Volevamo che ogni chiamata a record_score iniziasse con una list vuota, a meno che non ne fornissimo una esplicitamente.
Per evitare questo problema, una pratica comune è utilizzare None come valore di default per gli argomenti che possono essere mutabili. Poi, all'interno della funzione, puoi creare un nuovo oggetto mutabile se l'argomento è None. Ecco come potresti riscrivere la funzione record_score per risolvere il problema:
def record_score(new_score, score_list=None):
    if score_list is None:  # If no list was provided,
        score_list = []     # create a new one
    score_list.append(new_score)
    return score_list

print(record_score(95))  # [95]
print(record_score(85))  # [85]
In questa versione corretta, ogni chiamata a record_score che non fornisce una list personalizzata ottiene una list completamente nuova. In questo modo, i punteggi non vengono condivisi tra le varie chiamate.
💡
Quindi, il punto principale è questo: Gli argomenti di default mutabili in Python possono generare comportamenti imprevisti perché vengono creati una sola volta, e lo stesso oggetto viene riutilizzato a ogni chiamata della funzione. Questo potrebbe non essere ciò che vuoi, specialmente se modifichi l’oggetto mutabile. Per evitare questo problema, puoi usare None come valore di default e creare un nuovo oggetto all’interno della funzione, se necessario.
 
To check your solution you need to sign in
Sign in to continue