ProgrammazioneSviluppatore Backend

Che cos'è il passaggio di argomenti per riferimento e per valore in Python? Come Python implementa questo meccanismo e perché è importante distinguerli nella progettazione delle funzioni?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Comprendere come Python passa gli argomenti alle funzioni è estremamente importante per prevenire cambiamenti imprevisti nei dati e per una corretta progettazione del codice.

Storia della questione

Nei linguaggi di programmazione tradizionali, come C o Java, si utilizza il passaggio per valore (copy by value) o per riferimento (copy by reference). Tuttavia, in Python esiste un modello diverso — call by object reference (a volte chiamato "call by sharing").

Problema

Molti sviluppatori pensano erroneamente che Python passi sempre gli argomenti o per riferimento o per valore. Questo porta inevitabilmente a situazioni in cui gli oggetti mutabili vengono inaspettatamente modificati nel codice chiamante.

Soluzione

In Python i valori dei parametri della funzione sono riferimenti agli oggetti che vengono passati alla funzione. Questo significa:

  • Se l'oggetto è mutabile (mutable: list, dict, set…) — all'interno della funzione può essere modificato, e questo si rifletterà all'esterno.
  • Se l'oggetto è immutabile (immutable: int, str, tuple, frozenset), il tentativo di modificarlo all'interno della funzione porterà alla creazione di un nuovo oggetto e non influenzerà l'esterno.

Esempio:

# list - mutabile (mutable) def add_item(lst): lst.append(42) my_list = [1, 2, 3] add_item(my_list) print(my_list) # [1, 2, 3, 42] # int - immutabile (immutable) def add_num(x): x = x + 1 num = 10 add_num(num) print(num) # 10

Caratteristiche chiave:

  • Gli oggetti mutabili possono essere modificati all'interno della funzione — queste modifiche sono visibili all'esterno.
  • Gli oggetti immutabili non vengono influenzati dalla funzione — vengono solo creati nuovi oggetti.
  • Python non copia mai automaticamente gli argomenti, anche le strutture mutabili vengono sempre passate "per riferimento".

Domande trabocchetto.

Vengono sempre passati per riferimento gli argomenti in Python?

No, in Python vengono passati riferimenti agli oggetti, e come si comporta un oggetto dipende da se è mutabile o meno. Un oggetto immutabile, in caso di modifica, creerà sempre un nuovo oggetto.

È possibile riassegnare un argomento mutabile in una funzione e far sì che questo influisca sull'oggetto esterno?

No. Se dentro la funzione assegni un nuovo valore a un parametro, l'oggetto esterno non cambierà — stai solo cambiando un riferimento locale.

Esempio:

def reassign_list(lst): lst = [99, 100] my_list = [1, 2, 3] reassign_list(my_list) print(my_list) # [1, 2, 3]

Perché una funzione che accetta un list per default può comportarsi in modo strano a chiamate successive?

Perché il valore predefinito viene creato una sola volta — al momento della definizione della funzione, e se viene modificato (ad esempio, aggiungendo un elemento), verrà modificato per tutte le chiamate successive.

def add_element(x, cache=[]): cache.append(x) return cache print(add_element(1)) # [1] print(add_element(2)) # [1, 2]

Errori tipici e anti-pattern

  • Uso di argomenti mutabili per default (come nell'ultimo esempio).
  • Aspettarsi che una funzione non modifichi un list o dict passato, anche se lo modifica.
  • Confondere gli effetti delle funzioni lavorando con oggetti mutabili e immutabili.

Esempio dalla vita reale

Caso negativo

Un programmatore passa un elenco a una funzione e si aspetta che il suo elenco originale non cambi, ma la funzione aggiunge un elemento.

Pro:

  • Velocità, nessuna copia dei dati.

Contro:

  • Effetti collaterali imprevisti, bug nel codice complesso, se qualcuno non è a conoscenza delle modifiche all'argomento.

Caso positivo

Un programmatore copia esplicitamente l'elenco all'interno della funzione, se deve restituire qualcosa ma non modificare l'originale:

def process_data(data): data = data.copy() # o list(data) # lavoro sicuro con la copia data.append('report') return data

Pro:

  • Nessun effetto collaterale indesiderato, l'originale è protetto.

Contro:

  • Con oggetti grandi — costi di memoria/tempo per la copia.