2010-09-01 18 views
5

Cosa succede con la mia variabile Python? old_pos sembra essere legato a pos:Stranalità variabile di Python?

Codice:

pos = [7, 7] 
direction = [1, 1] 
old_pos = pos 
print 'pos  = '+str(pos) 
print 'old_pos = '+str(old_pos) 
pos[0] += direction[0] 
pos[1] += direction[1] 
print 'pos  = '+str(pos) 
print 'old_pos = '+str(old_pos) 

uscita:

pos  = [7, 7] 
old_pos = [7, 7] 
pos  = [8, 8] 
old_pos = [8, 8] 

Tuttavia, se sostituisco old_pos = pos con old_pos = tuple(pos) o addirittura old_pos = list(pos), non ottengo questo problema:

pos  = [7, 7] 
old_pos = [7, 7] 
pos  = [8, 8] 
old_pos = [7, 7] 
+2

Sì, questo è ciò che = = 'fa. :-) – Ken

+1

non ci sono variabili in python, solo nomi e oggetti. – hop

+0

@hop: Ma non sono le variabili di riferimento dei nomi? – recursive

risposta

12

Quando si dice old_pos = pos, non si sta creando una copia di pos, ma solo facendo un altro riferimento alla stessa lista. Se si desidera che due elenchi si comportino in modo indipendente, è necessario creare una copia, ad esempio utilizzando la funzione list(pos) come si menziona o utilizzando la notazione di sezione pos[:].

3

old_pos sembra essere legato a pos

corretto - questo:

old_pos = pos 

rende old_pos e pos puntano alla stessa lista. Non crea una nuova copia di pos.

3

ricorsivo è giusto per la causa. Si può vedere che hanno indirizzi di memoria identici:

>>> pos = [7, 7] 
>>> old_pos = pos 
>>> id(pos) 
4299304472 
>>> id(old_pos) 
4299304472 

questo è chiamato passaggio per riferimento, rispetto passaggio per valore. È inoltre possibile porre rimedio a questa situazione utilizzando il modulo copy.

>>> from copy import copy 
>>> pos = [7, 7] 
>>> old_pos = pos 
>>> id(pos) 
4299304472 
>>> id(old_pos) 
4299304472 
>>> old_pos = copy(pos) 
>>> id(old_pos) 
4299349240 
+3

Um ... in realtà non * passa per riferimento * perché non stai ** passando ** nulla nell'esempio. È solo che i nomi Python hanno * semantica di riferimento * nel modo in cui si riferiscono agli oggetti Python. –

7

old_pos = pos non crea una copia dell'oggetto riferito a dal nome pos, anzi crea un secondo riferimento chiamato old_pos per lo stesso oggetto. Le azioni eseguite su pos riguardano lo stesso oggetto indicato da old_pos. Allo stesso modo, i nomi "Steven" e "Mr. Rumbalski" si riferiscono entrambi a me. Se colpisci in faccia Steven, il signor Rumbalski sarà ferito, perché i due nomi si riferiscono allo stesso oggetto - io.

Ecco 3 modi per fare una copia reale invece di un secondo riferimento:

Uso fetta notazione

old_pos = pos[:] 

Tramite l'elenco costruttore

old_pos = list(pos) 

Utilizzando il modulo di copia

from copy import copy 
old_pos = copy(pos) 

Si noti che queste copie sono tutte copie poco profonde, che in questo caso vanno bene.Per conoscere la differenza tra copia superficiale e copia profonda, leggi documentation of the copy module.

+0

+1 metafora eccellente. –

0

Oltre ai suddetti commenti, è necessario eseguire alcuni passaggi aggiuntivi in ​​caso di array multidimensionali. Ad esempio, se si dispone di un array bidimensionale a = [[0,1,2],[3,4],[5,6,7,8]], il codice b = a non creerà una copia indipendente. Tuttavia, creerà un altro riferimento ai riferimenti delle stesse liste dimensionali all'interno dell'elenco bidimensionale. Per risolvere questo, è necessario utilizzare uno dei metodi di cui sopra per ogni lista all'interno della lista bidimensionale. Ad esempio, b = [i[:] for i in a] creerà una copia indipendente dell'elenco.