嵌套列表索引
我已经遇到了一些问题,在代码中使用了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