Python - 切片行为列表

Dan*_*Doe 1 python list-comprehension list

当我定义一个列表并尝试更改单个项目时,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

它按预期工作.但是当我尝试使用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
Run Code Online (Sandbox Code Playgroud)

它会导致列表中的整列项目发生更改.为什么是这样?如何通过列表理解达到预期的效果?

lvc*_*lvc 5

想想你是否这样做:

>>> row = ['a' for range in xrange(3)]
>>> row2 = row
>>> row2[0] = 'b'
>>> row
['b', 'a', 'a']
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为row并且row2同一列表的两个不同名称(您有row is row2) - 您的嵌套列表示例只会略微模糊这一点.

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

list_of_lists = [['a' for range in xrange(3)] for _ in xrange(3)]
Run Code Online (Sandbox Code Playgroud)

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

list_of_lists = [row[:] for range in xrange(3)]
Run Code Online (Sandbox Code Playgroud)

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

from copy import copy
list_of_lists = [copy(row) for range in xrange(3)]
Run Code Online (Sandbox Code Playgroud)

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