problem jest spowodowany faktem, że Python wybiera przekazywanie list przez odniesienie.
Normalnie zmienne są przekazywane „wartością”, a więc działają one niezależnie:
>>> a = 1
>>> b = a
>>> a = 2
>>> print b
1
Ale ponieważ list może dostać dość duże, zamiast przesuwania całą listę wokół pamięci, Python zdecyduje się po prostu użyć odniesienia ("wskaźnik" w kategoriach C). Jeśli przypiszesz jedną do drugiej zmiennej, przypisujesz do niej tylko odniesienie. Oznacza to, że można mieć dwie zmienne wskazujące na tej samej liście w pamięci:
>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]
Tak więc, w pierwszym wierszu kodu masz 4 * [0]
. Teraz [0]
jest wskaźnikiem do wartości 0 w pamięci, a po pomnożeniu otrzymujesz cztery wskaźniki w tym samym miejscu w pamięci. Ale kiedy zmienić jedną z wartości następnie Python wie, że musi zmienić wskaźnik do punktu do nowej wartości:
>>> a = 4 * [0]
>>> a
[0, 0, 0, 0]
>>> [id(v) for v in a]
[33302480, 33302480, 33302480, 33302480]
>>> a[0] = 1
>>> a
[1, 0, 0, 0]
Problem pojawia się, gdy pomnożymy tę listę - masz cztery kopie wskaźnika listy. Teraz po zmianie jednego z wartościami w jednej listy, wszystkie cztery razem zmiana:
>>> a[0][0] = 1
>>> a
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]
Rozwiązaniem jest uniknąć drugiego mnożenia. Pętla spełnia swoje zadanie:
>>> some_list = [(4 * [0]) for _ in range(4)]
Tu jest link do przewodnika na idiomatycznym programowania Python. Niektóre z nich są nieaktualne, ale część dotycząca zmiennych i nazw nadal ma znaczenie: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables – pcurry