|
Un elemento importante è che i parametri vengono passati SEMPRE per
riferimento, perfino i numeri. Nel caso di numeri però un eventuale
assegnamento crea un collegamento a un nuovo oggetto, e il numero originale
rimane immutato. Quindi consideriamo queste due funzioni:
def sum(x,y):
x = x + y
return x
def conc(l,o):
l.append(o)
return l
Notare quello che succede:
>>> z = 4
>>> sum(z,1)
5
>>> z
4
Però non è sempre così "innocuo": se per esempio passiamo una lista, se
questa viene modificata, la modifica si propaga al chiamante. Consideriamo
un altro esempio:
>>> l = [1,2]
>>> conc(l,3)
[1,2,3]
>>> l
[1,2,3]
In questo secondo caso le cose sono andate diversamente: l'oggetto
passato come parametro risulta modificato. In realtà non è che la modalià di
chiamata è diversa, ma agiamo sull'oggetto passato invece di crearne uno
nuovo.
Se si vuole evitare questo comportamento, si può ricorrere alla creazione
di una copia dell'oggetto come in questo modo:
>>> l = [1,2,3]
>>> conc(l[:],4)
[1,2,3,4]
>>> l
[1,2,3]
Utilizzando la sintassi "l[:]" abbiamo forzato la creazione di una copia
di l (cioè una slice completa di l), ed è il puntatore a questa copia che è
stato passato come parametro. Per questo motivo le variabili originale non è
stata modificata.
In generale bisogna stare abbastanza attenti a questo comportamento: è
abbastanza facile ottenere modifiche indesiderate. Come regola generale si
dovrebbe sempre pensare che un oggetto passato come parametro può essere
modificato. Se non si vuole questo, si devono fare delle copie.
Come protezione, alcuni oggetti sono per loro natura immutabili. Per
esempio le stringhe e le tuple. Con le stringhe non possiamo fare (come con
le liste) qualcosa come "s.append('c')" ad una stringa. Semplicemente
l'operazione non è disponibile. Occorre invece fare "s=s+ 'c'", e il
risultato è che viene creata una copia della stringa modificata.
(Grazie a Gabriele Renzi per le correzioni suggeritemi in questa sezione)
|