且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么创建列表列表会产生意外行为?

更新时间:2022-05-28 23:10:51

执行以下操作:

[[]]*n

您首先要创建一个列表,然后将*运算符与int n结合使用.这将获取列表中的所有对象,并对其进行n次重复.

You are first creating a list, then using the * operator with an int n. This takes whatever objects are in your list, and creates n- many repetitions of it.

但是由于在Python中,显式比隐式好,所以您不必隐式地复制这些对象.确实,这与Python的语义是一致的.

But since in Python, explicit is better than implicit, you don't implicitly make a copy of those objects. Indeed, this is consistent with the semantics of Python.

尝试命名一个示例,其中Python 隐式进行复制.

Try to name a single case where Python implicitly makes a copy.

此外,它与列表中的添加内容一致:

Furthermore, it is consistent with the addition on the list:

l = [1, [], 'a']

l2 = l + l + l

l[1].append('foo')

print(l2)

输出:

[1, ['foo'], 'a', 1, ['foo'], 'a', 1, ['foo'], 'a']

现在,正如注释中指出的那样,来自C ++的上述含义将是令人惊讶的,但是如果将其用于Python,则以上就是期望.

Now, as noted in the comments, coming from C++ it makes sense that the above would be surprising, but if one is used to Python, the above is what one would expect.

另一方面:

[[] for _ in range(5)]

是列表理解.等效于:

lst = []
for _ in range(5):
    lst.append([])

很明显,每次您在循环中时,都会创建一个新列表.这就是文字语法的工作原理.

Here, clearly, every time you are in the loop you create a new list. That is how literal syntax works.

顺便说一句,除了我喜欢的一个特定习惯用法外,我几乎从不在列表上使用*运算符:

As an aside, I almost never use the * operator on lists, except for one particular idiom I am fond of:

>>> x = list(range(1, 22))
>>> it_by_three = [iter(x)]*3
>>> for a,b,c in zip(*it_by_three):
...    print(a, b, c)
...
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
16 17 18
19 20 21