12

以下に示すコードでPythonのネストされたリストを使用することで、いくつかの問題が発生しました。

基本的に、2Dリストにはすべて0の値が含まれているので、ループでリスト値を更新したいと思います。

ただし、Pythonは私が望む結果を生成しません。私が誤解していることrange()やPythonリストのインデックスはありますか?

some_list = 4 * [(4 * [0])]
for i in range(3):
    for j in range(3):
        some_list[i+1][j+1] = 1
for i in range(4):
    print(some_list[i])

私が期待した結果は次のとおりです。

[0, 0, 0, 0]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]

しかし、Pythonの実際の結果は次のとおりです。

[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]
[0, 1, 1, 1]

何が起きてる?

4

2 に答える 2

20

この問題は、Pythonが参照によってリストを渡すことを選択したことが原因で発生します。

通常、変数は「値で」渡されるため、独立して動作します。

>>> a = 1
>>> b = a
>>> a = 2
>>> print b
1

ただし、リスト全体がメモリ内で移動するのではなく、リストがかなり大きくなる可能性があるため、Pythonは参照(C用語では「ポインタ」)のみを使用することを選択します。1つを別の変数に割り当てる場合は、その変数への参照のみを割り当てます。これは、メモリ内の同じリストを指す2つの変数を持つことができることを意味します。

>>> a = [1]
>>> b = a
>>> a[0] = 2
>>> print b
[2]

したがって、コードの最初の行にはがあります4 * [0]。これ[0]は、メモリ内の値0へのポインタであり、これを乗算すると、メモリ内の同じ場所への4つのポインタが得られます。しかし、値の1つを変更すると、Pythonは、新しい値を指すようにポインターを変更する必要があることを認識します。

>>> 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]

このリストを乗算すると問題が発生します。リストポインタのコピーが4つ取得されます。これで、1つのリストの値の1つを変更すると、4つすべてが一緒に変更されます。

>>> a[0][0] = 1
>>> a
[[1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]

解決策は、2番目の乗算を回避することです。ループがその役割を果たします。

>>> some_list = [(4 * [0]) for _ in range(4)]
于 2012-10-24T22:28:33.030 に答える
8

実際には、リスト内のすべてのオブジェクトは同じであるため、1つを変更すると、他のオブジェクトも変更されます。

In [151]: some_list = 4 * [(4 * [0])]  

In [152]: [id(x) for x in some_list]
Out[152]: [148641452, 148641452, 148641452, 148641452]

In [160]: some_list[0][1]=5  #you think you changed the list at index 0 here

In [161]: some_list
Out[161]: [[0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0]]  #but all lists are changed

次の方法でリストを作成します。

In [156]: some_list=[[0]*4 for _ in range(4)]

In [157]: some_list
Out[157]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

In [158]: [id(x) for x in some_list]
Out[158]: [148255436, 148695180, 148258380, 148255852]

In [163]: some_list[0][1]=5

In [164]: some_list
Out[164]: [[0, 5, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]  #works fine in this case
于 2012-10-24T21:59:45.223 に答える