2013-01-07 12 views
5

Sto imparando Python e ho cercato di creare un deque. Tuttavia, ottengo risultati errati e non sono sicuro del perché. Il mio codice è il seguente:scope in Python deque?

p = [2, 1], [1, 1] 
init_q= deque() 

init_q.append(p) 
for i in range(len(p)): 
    for j in range(len(p[i])): 
     temp = p[i][j] 
     p[i][j] = 0 
     init_q.append(p) 
     p[i][j] = temp 

while init_q: 
    print init_q.pop() 

In questo codice prendo in un elenco, poi ho voglia di creare una coda con 5 lista, di cui 4 hanno un 0 in loro in luoghi diversi, il risultato che voglio è :

([2, 1], [1, 1]) 
([0, 1], [1, 1]) 
([2, 0], [1, 1]) 
([2, 1], [0, 1]) 
([2, 1], [1, 0]) 

Tuttavia, il risultato che ottengo è:

([2, 1], [1, 1]) 
([2, 1], [1, 1]) 
([2, 1], [1, 1]) 
([2, 1], [1, 1]) 
([2, 1], [1, 1]) 
+0

Sei sicuro che l'output previsto non è arretrato? – abarnert

risposta

3

Ho creato un visualization su Python Tutor semplificando il codice. Vagabondare e si può facilmente vedere cosa sta succedendo.

Una singola modifica al codice può risolvere il problema.

init_q.append(map(list, p)) # Initialize a new list from p's element lists 

Ecco lo visualization utilizzando la modifica di cui sopra.

4

si sta mettendo un oggetto nel deque, quindi modificando l'oggetto. Di fatto, metti sempre lo stesso oggetto nella deque, quindi tutti i deque hanno riferimenti a un oggetto p.

+0

E per aggirare questo problema, vorresti ...? –

+2

Crea una copia dell'oggetto - 'p [:]', o se non funziona, crea una 'deepcopy' dell'elenco usando il modulo' copia', quindi aggiungi * la * copia * alla lista. – Volatility

+0

Grazie non sapevo cosa stavo cercando ma ho risolto. 'p [:]' non ha funzionato, ma 'deepcopy' ha funzionato. Quindi ora sembra: 'newobj = copy.deepcopy (p)' 'newobj [i] [j] = 0' ' init_q.append (newobj) ' – Sjieke

1

In seguito il mio commento alla risposta di Ned Batchelder, ecco come si potrebbe fare la stessa cosa immutabilmente:

for i in range(len(p)): 
    for j in range(len(p[i])): 
     temprow = [0 if y==j else p[i][y] for y in range(len(p[i]))] 
     temp = [temprow if x==i else p[x] for x in range(len(p))] 
     init_q.append(temp) 

In questo caso, penso che il risultato è molto meno leggibile il suo suggerimento:

 temp = copy.deepcopy(p) 
     temp[i][j] = 0 
     init_q.append(temp) 

Come ho detto, a volte rende le cose più semplici, a volte meno semplici ... Ma il punto è che è più facile ragionare. Non devi preoccuparti se più list s in -o, peggio, sotto-list s-sono identità di condivisione.

Se il tradeoff vale la pena è in realtà una decisione caso per caso, e probabilmente diversa per ogni programmatore. In questo caso, non utilizzerei la soluzione immutabile e dubito che molti altri programmatori (Python) lo farebbero. Ma vale la pena saperlo scrivere.

Si potrebbe anche considerare di scrivere questo come un elenco 3D, invece di un elenco di elenchi 2D e quindi inserirlo in deque. E 'ovviamente equivalente, ma concettualmente potrebbe essere più semplice di pensare a questo modo:

init_q.append(p) 
q = [copy.deepcopy(p) for i in range(len(p)) for j in range(len(p[i]))] 
for i in range(len(p)): 
    for j in range(len(p[i])): 
     q[i*len(p[i])+j][i][j] = 0 
init_q.extend(q) 

PS, se si sta facendo un sacco di questo genere di cose, si consiglia di dare un'occhiata a numpy. Se questo è il tuo intero problema, non ti farà nulla di buono ... ma se fai qualcosa di più complicato con gli array multidimensionali, lo farà.