Python - 切片行为列表

时间:2012-09-17 03:22:26

标签: python list list-comprehension

当我定义列表并尝试更改单个项目时:

list_of_lists = [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
    print row

按预期工作。但是当我尝试使用list comprehension来创建列表时:

row = ['a' for range in xrange(3)]
list_of_lists = [row for range in xrange(3)]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
    print row

导致列表中的整列项目发生变化。为什么是这样?如何通过列表理解实现预期的效果?

3 个答案:

答案 0 :(得分:5)

想想你是否这样做:

>>> row = ['a' for range in xrange(3)]
>>> row2 = row
>>> row2[0] = 'b'
>>> row
['b', 'a', 'a']

这是因为rowrow2相同列表的两个不同名称(你有row is row2) - 你的嵌套列表示例只会模糊这个一点。

要使它们成为不同的列表,您可以使它每次重新运行列表创建代码,而不是执行变量赋值:

list_of_lists = [['a' for range in xrange(3)] for _ in xrange(3)]

或者,每次使用完整旧列表的片段创建一个新列表:

list_of_lists = [row[:] for range in xrange(3)]

虽然这并不能保证所有序列都能正常工作 - 只是列表切片会为切片创建一个新列表。例如,numpy数组不会发生这种情况 - 其中的切片是数组的一部分视图而不是副本。如果您需要更多地工作而不仅仅是列表,请使用copy模块:

from copy import copy
list_of_lists = [copy(row) for range in xrange(3)]

另外,请注意range不是变量的最佳名称,因为它会影响内置函数 - 对于像这样的一次性,_是相当常见的。

答案 1 :(得分:2)

这是因为python中的大多数对象(exept用于字符串和数字)都被传递了引用(不完全是通过引用,但是here你有更好的解释)所以当你尝试在“list comprehensive”中这样做时“方式,你得到一个列表3列表相同的列表(你称之为”行“)。因此,当您更改一行的值时,您会看到所有行的更改)

所以你需要做的是改变你的“矩阵”创作:

list_of_lists = [list(row) for range in xrange(3)]

Here您对如何正确获取列表副本有一些想法。根据您的目的,您可以使用其中一个......

希望它有所帮助!

答案 2 :(得分:0)

复制列表而不仅仅是参考。

list_of_lists = [row[:] for range in xrange(3)]