Come passare un valore per riferimento in Python

di Lorenzo Neri
Published: Last Updated on

Come passare un valore per riferimento in Python? Esiste un modo per gestire i valori “by reference”? Scoprilo assieme a me in questo articolo!

In Python, a differenza di quanto accade in altri linguaggi come PHP oppure C#, se volessi passare un valore per riferimento non hai a tua disposizione degli operatori ben specifici.

Non solo: la documentazione di Python con l’esempio fornito, non sembra troppo convincente.

Ciao mi chiamo Lorenzo Neri e sono un informatico: realizzo contenuti per aiutare le persone a padroneggiare l’arte del nuovo millennio, ovvero l’informatica!

Per intenderci:

class PassaPerReference:
    def __init__(self):
        self.variabile = 'Originale'
        self.cambia(self.variabile)
        print(self.variabile)
    def cambia(self, var):
        var = 'Cambiato'

Eppure sembra che il valore non cambi affatto: che fare allora?

Passare per riferimento: ragioniamo in due passi

In Python abbiamo a che fare con due fattori da prendere in considerazione in questo caso.

  1. Il parametro che stiamo passando è attualmente la referenza ad un oggetto, ma se ci fai caso nell’esempio di prima è passata per valore.
  2. Alcuni tipi di dato sono mutabili ma altri no.

Che significa ciò che ho appena scritto? Beh diciamo che in sintesi significa appunto prendere in considerazione due aspetti.

Se stai cercando di passare un oggetto mutabile all’interno di un metodo, il metodo stesso ottiene il riferimento allo stesso oggetto. Quindi, puoi certamente mutarlo, ma lo scope esterno non ne è a conoscenza: che significa? Che la referenza esterna al metodo sta puntando all’oggetto originale.

In sintesi: non è il modo corretto di passare un valore per riferimento in Python.

Dobbiamo però parlare degli oggetti immutabili. Se ripetiamo il processo che ti ho appena esposto, non cambia nulla, eccezion fatta che l’oggetto stesso non potrà nemmeno essere mutato.

Ciò detto, cerchiamo di capire come passare un valore per riferimento, ma seguendo le due tipologie di oggetti che abbiamo in Python.

Passare un valore per riferimento: tipi mutabili

Usiamo nel nostro esempio una lista, quindi eseguiremo il processo “pass by reference” di un mutable.

Facciamo l’esempio a seguire:

def provo_a_cambiare_i_contenuti_della_lista(la_lista):
    print('ottengo', la_lista)
    la_lista.append('quattro')
    print('modificato in', la_lista)
lista_esterna = ['uno', 'due', 'tre']
print('prima, lista_esterna =', lista_esterna)
provo_a_cambiare_i_contenuti_della_lista(lista_esterna)
print('dopo, lista_esterna =', lista_esterna)

Abbastanza lineare e pratico no? Ecco, questo è l’output:

prima, lista_esterna = ['uno', 'due', 'tre']
ottengo ['uno', 'due', 'tre']
modificato in ['uno', 'due', 'tre', 'quattro']
dopo, lista_esterna = ['uno', 'due', 'tre', 'quattro']

Per fartela breve, ciò che succede è che il parametro è passato per riferimento tramite “lista_esterna” e NON con una sua copia.

Siccome stiamo usando un mutable otteniamo il nostro scopo e le modifiche ottenute grazie al “pass by reference” si mantengono anche nello scope esterno al metodo!

Ora, vediamo come possiamo passare per riferimento nel secondo caso.

Passare un valore per riferimento: tipi immutabili

In questo caso ripetiamo il cinema del “pass by reference” di un immutable. Con chi? Con una stringa.

Proviamoci con il seguente esempio:

def provo_a_cambiare_la_stringa_per_referenza(la_stringa):
    print('ottengo', la_stringa)
    la_stringa = 'Sto cercando di fare riferimento...'
    print('modifico in', la_stringa)
stringa_esterna = 'Stavo cercando di fare riferimento'
print('prima, stringa_esterna =', stringa_esterna)
provo_a_cambiare_la_stringa_per_referenza(stringa_esterna)
print('dopo, stringa_esterna =', stringa_esterna)

Guarda un po’ cosa succede:

prima, stringa_esterna = Stavo cercando di fare riferimento
ottengo Stavo cercando di fare riferimento
modifico in Sto cercando di fare riferimento...
dopo, stringa_esterna = Stavo cercando di fare riferimento

Il parametro “la_stringa” è passato per valore e di fatto le modifiche NON si mantengono nello scope esterno.

In questo caso, ciò che avviene è una vera e propria generazione di una copia e di fatto non abbiamo alcuna modifica concreta al di fuori del metodo stesso.

Continua a scoprire di più con questi articoli!

2 commenti

Umberto 29/06/2023 - 08:08

Stai confondendo concetti molto diversi.
Il passaggio per riferimento è una cosa completamente diversa da quello che tu dici e Python non la fa.
Concettualmente immagina di passare una Persona ad una funzione. Ad esempio Lorenzo.
Se tu passi Lorenzo ad una funzione Python, al termine quella variabile non può contenere un’altra persona (ad esempio Marco).
In Python (e in Java), quello che puoi fare è cambiare il contenuto della persona Lorenzo, ad esempio dire che ha un anno in più o ha cambiato nome (ad esempio ora si chiama Marco) o quello che vuoi ma Lorenzo hai passato e Lorenzo rimane.
Ovviamente, l’insieme a cui appartiene Lorenzo (l’insieme delle persone o, se preferisci, la classe Persona o il tipo di dato Persona), deve essere mutable altrimenti non puoi fare neanche quello.
Discorso completamente diverso e moooooolto più complicato è il passaggio per riferimento (in generale i puntatori).

Rispondi
Lorenzo Neri 02/07/2023 - 12:28

Ciao Umberto e grazie per il tuo commento.

Nell’articolo viene spiegato come Python permette di effettuare ciò e gli esempi riportati sono pensati proprio per rispondere ai tuoi disappunti.

Un caro saluto,
Lorenzo

Rispondi

Lascia un commento

Questo sito potrebbe fare uso di cookie e siccome l'UE mi obbliga a fartelo presente, eccoti il classico banner dove puoi decidere come gestirli. Accetta Leggi di più