2013-09-06 22 views
5
class Board: 

    def __init__(self): 
     self.board = self.createBoard() 

    def createBoard(self): 
     line = [] 
     for i in range(7): 
      line.append(' ') 
     board = [] 
     for i in range(7): 
      board.append(line) 
     return board 

    def showBoard(self): 
     line = "| " 
     for x in range(len(self.board)): 
      for y in range(len(self.board)): 
       line += self.board[x][y] + " | " 
      print("-" * 29) 
      print(line) 
      line = "| " 
     print("-" * 29) 

if __name__ == '__main__': 
    board = Board() 
    board.showBoard() 
    board.board[1][1] = "O" 
    board.showBoard() 

Pracowałem nad demo/grą w python konsoli connect-4, kiedy utknąłem w tym naprawdę dziwnym zagadnieniu.Dwuwymiarowa lista błędnie przypisująca wartości w pythonie

Wyjście powyższego kodu jest następujący:

----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 

Dziwne jest to, że nigdy przypisany O do wszystkich tych pozycjach, tylko przypisuje go do pozycji [1] [1].

spodziewał I wyjście będzie:

----------------------------- 
| | | | | | | | 
----------------------------- 
| | O | | | | | | 
----------------------------- 
| | | | | | | | 
----------------------------- 
| | | | | | | | 
----------------------------- 
| | | | | | | | 
----------------------------- 
| | | | | | | | 
----------------------------- 
| | | | | | | | 
----------------------------- 

Jest bardzo prawdopodobne, że brakuje mi czymś oczywistym i mały, ale szukałem i próbuje przez ponad godzinę, a ja naprawdę nie mogę znajdź problem.

To nie tak, że moja lista board.board jest bardziej dziwna niż jakakolwiek inna dwuwymiarowa lista.

[[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']] 

(To co mam, kiedy print(board.board))

Kopiowanie i wklejanie że w IDLE otrzymuję następujący:

>>> a = [[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']] 
>>> a[1][1] = "O" 
[[' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', 'O', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' '], [' ', ' ', ' ', ' ', ' ', ' ', ' ']] 

które dostaje mi właściwą wartość płyty.

Co jest takiego oczywistego w moim kodzie, że go brakuje? Jestem prawie pewien, że gdy ktokolwiek z was znajdzie odpowiedź, że wstrząśnie moją głową ze wstydem, prawdopodobnie jest tak źle.

Wystarczająca ilość samokaleczenia, dlaczego mój kod board.board[1][1] = "O" przypisuje wartość "O" do każdego wiersza w board.board?

Zmiana pierwszego 1 na inny od 0-6 również niczego nie zmienia. To wszystko jest takie samo.

+0

Jestem pewien, że jest to duplikat 100 innych pytań , ale niestety bardzo trudno jest znaleźć dobre warunki wyszukiwania, aby je znaleźć, więc trudno jest obwiniać kogokolwiek za powtórzenie pytania ... Niektóre z pytań z prawej strony są z pewnością powiązane, ale żaden z nich nie wydaje się być dupkami. – abarnert

Odpowiedz

6

Jest to wyjaśnione w FAQ, pod How do I create a multidimensional list?

Problem jest w tej części kodu:

board = [] 
for i in range(7): 
    board.append(line) 

Ty tworzysz listę 7 odniesienia do tej samej listy, line. Tak więc, kiedy modyfikujesz jedną, wszystkie pozostałe zmieniają się, ponieważ są one tą samą listą.

Rozwiązaniem jest stworzenie 7 oddzielnych list tak:

def createBoard(self): 
    board = [] 
    for i in range(7): 
     line = [] 
     for i in range(7): 
      line.append(' ') 
     board.append(line) 
    return board 

Albo prościej, oddzielnego kopii oryginalnej listy:

def createBoard(self): 
    line = [] 
    for i in range(7): 
     line.append(' ') 
    board = [] 
    for i in range(7): 
     board.append(line[:]) 
    return board 

Choć jesteśmy można go w ten sposób znacznie uprościć, korzystając ze sprawdzeń list:

def createBoard(self): 
    return [[' ' for j in range(7)] for i in range(7)] 

Albo, jak FAQ sugeruje, można zrobić lepiej użyć mądrzej wielowymiarowego obiektu Array, jak te NumPy lub pandy zapewniają:

def createBoard(self): 
    return np.tile(' ', (7, 7)) 

Wadą jest to, że trzeba będzie zainstalować numpy, ponieważ nie ma nic w standardowej bibliotece, która działa w ten sposób. Ale zaletą jest to, że masz potężne narzędzia do radzenia sobie z tablicami - a[1, 1] nie jest dużo prostsze niż a[1][1], ale dostęp do drugiej kolumny jest łatwiejszy niż [row[1] for row in a].

+0

Tak jak myślałem, coś małego i prostego. Dziękujemy za szybką odpowiedź i wybraną jako najlepszą odpowiedź, ponieważ zawiera ona również odniesienia do często zadawanych pytań. – Azeirah

0

To jest problem z pythonem za pomocą odnośników. Druga część CreateBoard

for i in range(7): 
     board.append(line) 

Umieszcza 7 odniesień do tej samej listy na zewnętrznej liście. Więc masz listę 7 kopii tej samej listy. Edytowanie wartości w jednej z tych podliści faktycznie aktualizuje je wszystkie, ponieważ odnoszą się one do tej samej pamięci.

Jedną z opcji byłoby wykorzystanie copy.deepcopy lub jawnie utworzyć nową listę dla każdej linii

import copy # at the top of the file 
for i in range(7): 
    board.append(copy.deepcopy(line)) 

LUB

for i in range(7): 
    board.append(list(' ' * 7))