简体   繁体   English

Python列表混乱

[英]Python list confusion

Let's say I have the following code: 假设我有以下代码:

a_list = [[0]*10]*10

This generates the following list: 这会生成以下列表:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

Then I want to modify the first element in the first list: 然后我想修改第一个列表中的第一个元素:

a_list[0][0] = 23

I expected only the first element of the list to be modified, but actually the first element of each list was changed: 我希望只修改列表的第一个元素,但实际上每个列表的第一个元素都被更改了:

[[23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [23, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

I managed to find another way to represent my data to avoid this but why is this happening? 我设法找到另一种方式来表示我的数据以避免这种情况,但为什么会发生这种情况呢? Why isn't just the first list changed? 为什么不只是第一个列表改变了? When I do the second *10 , does Python actually copy the first list's address instead of allocating a new memory block? 当我做第二个*10 ,Python实际上是复制第一个列表的地址而不是分配新的内存块吗?

Your hunch about copying addresses is correct. 你对复制地址的预感是正确的。 Think about it like this: 想想这样:

sub_list = [0] * 10
a_list = [sub_list] * 10

This code is actually equivalent to the code you have posted above. 此代码实际上等同于您在上面发布的代码。 What this means is that you are actually changing the same list sub_list whenever you change any element of a_list . 这意味着,无论何时更改a_list任何元素,您实际上都在更改相同的列表sub_list You can even make sure of it by typing: 您甚至可以通过键入以下内容来确保它:

a_list = [[0] * 10] * 10
for n in a_list:
    print id(n)

And it will show up the same for every element. 并且每个元素都会显示相同的内容。 To remedy this, you should use: 要解决这个问题,您应该使用:

a_list = [[0] * 10 for _ in range(10)]

In order to create a new sublist for every element of a_list . a_list每个元素创建一个新的子列表。

Lists contain references to objects. 列表包含对象的引用。 Multiplication on lists simply repeats the references (to the same objects!). 列表上的乘法只是重复引用(对于相同的对象!)。 While this is fine for immutable objects (like integers), what you are getting is multiple references to the same list . 虽然这对于不可变对象(如整数)来说很好,但你得到的是对同一个列表的多个引用。

Create separate lists with this pattern [[0]*10 for _ in xrange(10)] . 使用此模式创建单独的列表[[0]*10 for _ in xrange(10)]

Why isn't just the first list changed? 为什么不只是第一个列表改变了?

The reason is simple, there really is only 1 list, not 10 - just as you already suspected: 原因很简单,实际上只有1个列表,而不是10个 - 正如您已经怀疑的那样:

In [1]: [[0]*10]*10
Out[1]:
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

In [2]: map(id, _)
Out[2]:
[54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624,
 54094624]

If you want to create 10 lists, you can achieve this easily via an expression like 如果要创建10个列表,可以通过类似的表达式轻松实现

[[0]*10 for x in xrange(10)]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM