2013-01-07 10 views
5

Uczę się Pythona i próbuję stworzyć deque. Jednak otrzymuję niepoprawne wyniki i nie jestem pewien dlaczego. Mój kod wygląda następująco:Python deque scope?

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() 

W tym kodzie biorę na liście, to wtedy chcesz utworzyć kolejkę z 5 listy, z których 4 mają 0 w nich w różnych miejscach, w wyniku czego chcę to :

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

jednak wynik pojawia się:

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

Czy jesteś pewien, że oczekiwane dane wyjściowe nie są wyświetlane wstecz? – abarnert

Odpowiedz

3

Utworzyłem visualization na Pythonie Tutor, upraszczając kod. Fiddle around i możesz łatwo zobaczyć, co się dzieje.

Pojedyncza zmiana linii kodu może to naprawić.

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

Oto visualization za pomocą powyższej zmiany.

4

jesteś oddanie obiektu w deque, następnie zmienia obiekt. W rzeczywistości zawsze umieszczasz ten sam obiekt w deque, więc wszystkie deque mają odniesienia do jednego obiektu p.

+0

A żeby obejść ten problem, mógłbyś ...? –

+2

Utwórz kopię obiektu - 'p [:]', lub jeśli to nie działa, wykonaj 'deepcopy' listy używając modułu' copy', a następnie dołącz * * do listy. – Volatility

+0

Dzięki Nie wiedziałem, czego szukam, ale rozwiązałem. 'p [:]' nie działało, ale 'deepcopy' zrobił. Teraz wygląda na to: 'newobj = copy.deepcopy (p)' 'newobj [i] [j] = 0' ' init_q.append (newobj) ' – Sjieke

1

Kontynuując mój komentarz Aby odpowiedzieć Ned Batchelder, oto w jaki sposób można zrobić to samo niezmiennie:

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) 

W tym przypadku, myślę, że wynik jest dużo mniej czytelny niż jego sugestia:

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

Jak już mówiłem, czasami sprawia to, że rzeczy są prostsze, czasem mniej proste ... Ale chodzi o to, że łatwiej jest o tym myśleć. Nie musisz się martwić o to, czy wiele numerów list w init_q -lub gorzej, sub-list w tych list s-udostępni tożsamość.

Niezależnie od tego, czy koszt jest wartościowy, jest to decyzja indywidualna i prawdopodobnie inna dla każdego programisty. W tym przypadku nie użyłbym niezmiennego rozwiązania i wątpię, by wielu innych programistów (Python) mogło. Ale warto wiedzieć, jak to napisać.

Możesz także rozważyć zapisanie tego jako listy 3D zamiast listu 2D list, a następnie przesłanie go do deque. To oczywiście równoważne, ale koncepcyjnie może być prostsze, aby myśleć o tym tak:

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, jeśli robisz dużo tego typu rzeczy, może chcesz przyjrzeć numpy. Jeśli to jest twój cały problem, nic ci to nie pomoże ... ale jeśli zrobisz coś bardziej skomplikowanego z wielowymiarowymi tablicami, to to zrobi.