嵌套列表索引

我已经遇到了一些问题,在代码中使用了Python中的嵌套列表bleow。

基本上,我有一个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] 

这里发生了什么?

这个问题是由pythonselect通过引用传递列表引起的。

通常variables是“按值”传递的,所以它们独立运作:

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

但是由于列表可能会变得非常大,而不是将整个列表转移到内存中,所以Pythonselect使用引用(以C语言表示的“指针”)。 如果您将一个variables分配给另一个variables,则只分配对其的引用。 这意味着你可以有两个variables指向内存中的同一个列表:

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

所以,在你的第一行代码中你有4 * [0] 。 现在[0]是一个指向内存中值0的指针,当你乘以它时,你会得到四个指向内存中相同位置的指针。 但是当你改变其中的一个值的时候,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] 

当你乘以这个列表时,问题就来了 – 你得到了四个指针列表的副本。 现在当你改变一个列表中的一个值时,所有四个值一起改变:

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

解决办法是避免第二次乘法。 循环完成这项工作:

 >>> some_list = [(4 * [0]) for _ in range(4)] 

实际上你列表中的所有对象都是一样的,所以换个对象也是一样的:

 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 

用这种方式创build你的列表:

 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