2011-01-03 2 views
5

Pensavo di conoscere Python fino a stasera. Qual è il modo corretto di fare qualcosa di simile? Ecco il mio codice:Confusione di oggetti Python: a = b, modifica di b e una modifica!

a = ["one", "two", "three"] 
b = a # here I want a complete copy that when b is changed, has absolutely no effect on a 
b.append["four"] 
print a # a now has "four" in it 

In sostanza voglio sapere, al posto del passo b = a, come potrei correttamente fare una copia di una lista o un dizionario in modo che quando b viene modificato a non cambia con esso?

+5

Beh, non conosci Python. O almeno non ne conosci una parte importante, quali sono le variabili. Vedi una domanda simile su SO o ad es. http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables. – delnan

+5

@delnan per essere onesti, non è una trappola insolita per chi è nuovo in Python per capire che l'assegnazione variabile che coinvolge le liste assegna riferimenti, anche se l'affermazione "Pensavo di conoscere Python" tende a indicare che non sono "nuovi": –

risposta

11

Quello che stai vivendo è il concetto di riferimenti. Tutti gli oggetti in Python hanno un riferimento e quando si assegnano uno o due nomi a e b, questo risulta sia in a e b che punta allo stesso oggetto .

>>> a = range(3) 
>>> b = a      # same object 
>>> b.append(3) 
>>> a, b      # same contents 
([0, 1, 2, 3], [0, 1, 2, 3]) 

Con le liste, è possibile effettuare creare un nuovo elenco b che è una copia di un altro a usando b = a[:].

>>> a = range(3) 
>>> b = a[:]     # make b a new copy of a 
>>> b.append(3) 
>>> a, b      # a is left unchanged 
([0, 1, 2], [0, 1, 2, 3]) 

Per una soluzione più generale per qualsiasi oggetto, utilizzare il copy module. Una copia superficiale copierà i riferimenti memorizzati all'interno dell'oggetto che stai copiando, mentre una copia profonda eseguirà ricorsivamente nuove copie di tutti gli oggetti.

>>> a = [range(2), range(3)] 
>>> b = copy.copy(a)   # shallow copy of a, equivalent to a[:] 
>>> b[0] = range(4) 
>>> a, b      # setting an element of b leaves a unchanged 
([[0, 1], [0, 1, 2]], [[0, 1, 2, 3], [0, 1, 2]]) 
>>> b[1].append(3) 
>>> a, b      # modifying an element of b modifies the element in a 
([[0, 1], [0, 1, 2, 3]], [[0, 1, 2, 3], [0, 1, 2, 3]]) 

>>> a = [range(2), range(3)] 
>>> b = copy.deepcopy(a)  # deep recursive copy of a 
>>> b[1].append(3) 
>>> a, b      # modifying anything in b leaves a unchanged 
([[0, 1], [0, 1, 2]], [[0, 1], [0, 1, 2, 3]]) 
+0

che cosa è una copia profonda e che cosa è una copia superficiale. ho notato che la dict.copy .__ doc__ string dice che è una copia "superficiale". qual è la differenza? – james

+5

Controlla http: // StackOverflow.it/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy – Sapph

+0

Questa è in realtà una copia superficiale, ma per il resto il modo giusto per copiare una lista. – Keith

1

la correttezza modo di copiare un oggetto è

from copy import copy 
a = [1, 2, 3] 
b = copy(a) 

Abbastanza semplice. C'è tasti di scelta rapida per le liste:

a = [1, 2, 3] 
b = a[:] 

C'è anche deepcopy() se si desidera copiare gli oggetti nel lista pure.

+0

Fai attenzione all'abuso di deepcopy. Questo può far esplodere l'utilizzo della memoria e, a volte, genera bizzarri errori di "unpicklable object". Per quasi tutti i casi d'uso non * è necessario * una copia, e per gli altri casi, una copia superficiale lo farà. – bukzor

1

Qui ci sono 3 modi per fare una copia della lista a:

Uso fetta notazione:

copy_of_a = a[:] 

utilizzare l'elenco costruttore:

copy_of_a = list(a) 

utilizzare il modulo di copia:

from copy import copy 
copy_of_a = copy(a) 

Queste sono tutte copie superficiali, sufficienti per la tua domanda. Per conoscere la differenza tra copia superficiale e copia profonda, leggi documentation of the copy module.