列表的列表更改出人意料地反映了

发布于 2025-01-22 03:35:55 字数 946 浏览 0 评论 0 原文

我创建了一个列表:

>>> xs = [[1] * 4] * 3
>>> print(xs)
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

然后,我更改了最内在的值之一:

>>> xs[0][0] = 5
>>> print(xs)
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

我希望这仅影响第一个sublist,而不是全部。也就是说:

>>> print(xs)
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

为什么每个子列表的每个第一个元素都会更改为 5


另请参阅:

I created a list of lists:

>>> xs = [[1] * 4] * 3
>>> print(xs)
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

Then, I changed one of the innermost values:

>>> xs[0][0] = 5
>>> print(xs)
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

I expected this to only affect the first sublist, not all of them. That is:

>>> print(xs)
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

Why did every first element of every sublist change to 5?


See also:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

野稚 2025-01-29 03:35:55

当您编写 [X]*3 时,您可以获得列表 [x,x,x] 。也就是说,一个对相同 x 的参考的列表。然后,当您修改此单个 X 时,可以通过所有三个引用可见:

x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
    f"id(xs[0]): {id(xs[0])}\n"
    f"id(xs[1]): {id(xs[1])}\n"
    f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]

要修复它,您需要确保在每个位置上创建一个新列表。一种方法是

[[1]*4 for _ in range(3)]

每次将重新评估 [1]*4 ,而不是一次评估一次,而是将3个引用到1列表。


您可能想知道为什么*无法像列表理解的方式使独立对象。这是因为乘法操作员*在对象上操作,而无需看到表达式。当您使用*乘> [[1]*4] 乘以3,*仅看到1元素列表 [[[[[[[[[[[[[[[[[[[[[[] 1] * 4] 评估,而不是 [[1] * 4 表达式文本。 * 不知道如何抄袭该元素,不知道如何重新评估 [[1] * 4] ,而且一般不知道您甚至想要副本,甚至可能没有一种复制元素的方法。

唯一的选项*就是对现有的sublist进行新的引用,而不是试图制作新的sublist。其他任何事情都会不一致或需要重新设计基本语言设计决策。

相比之下,列表理解重新评估了每次迭代的元素表达式。 [[1] * 4 for N范围内(3)] 重新评估 [1] * 4 每次出于相同的原因 [x ** 2 for x for x在范围(3)中] 每次重新评估 x ** 2 [1] * 4 的每次评估都会生成一个新列表,因此列表理解可以完成您想要的。

顺便说一句, [1] * 4 也不复制 [1] 的元素,但这并不重要,因为整数是不可变的。您不能做 1. Value = 2 之类的事情,然后将1变成2。

When you write [x]*3 you get, essentially, the list [x, x, x]. That is, a list with 3 references to the same x. When you then modify this single x it is visible via all three references to it:

x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
    f"id(xs[0]): {id(xs[0])}\n"
    f"id(xs[1]): {id(xs[1])}\n"
    f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048

x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]

To fix it, you need to make sure that you create a new list at each position. One way to do it is

[[1]*4 for _ in range(3)]

which will reevaluate [1]*4 each time instead of evaluating it once and making 3 references to 1 list.


You might wonder why * can't make independent objects the way the list comprehension does. That's because the multiplication operator * operates on objects, without seeing expressions. When you use * to multiply [[1] * 4] by 3, * only sees the 1-element list [[1] * 4] evaluates to, not the [[1] * 4 expression text. * has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4], and no idea you even want copies, and in general, there might not even be a way to copy the element.

The only option * has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.

In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)] reevaluates [1] * 4 every time for the same reason [x**2 for x in range(3)] reevaluates x**2 every time. Every evaluation of [1] * 4 generates a new list, so the list comprehension does what you wanted.

Incidentally, [1] * 4 also doesn't copy the elements of [1], but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2 and turn a 1 into a 2.

傲性难收 2025-01-29 03:35:55
size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]

< %20Size%0AMATRIX%20%3D%20%5B%5B%5D*size%20_%20_%20英寸20英寸20 range%28size%29%5D&amp; cumulative = false&amp; amp; curinstr = 9&amp; amp; amp; amp; heapprimitives = false&amp; amp; amp; mode = display&amp; amp; amp; amp; amp; amp; emp; amp》; arount arount = opt-frontend.js&amp; py = 3&amp; rawinputlstjson =%5b%5d&amp; amp; textreferences = false = false“ rel =“ noreferrer”>实时可视化使用python tutor:

size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for _ in range(size)]

Live visualization using Python Tutor:

Frames and Objects

缺⑴份安定 2025-01-29 03:35:55

实际上,这正是您所期望的。让我们分解此处发生的事情:

您编写的

lst = [[1] * 4] * 3

等同于:

lst1 = [1]*4
lst = [lst1]*3

这意味着 lst 是一个指向 lst1 的列表。这意味着以下两个行是等效的:

lst[0][0] = 5
lst1[0] = 5

AS lst [0] 不过是 lst1

为了获得所需的行为,您可以使用列表理解:

lst = [ [1]*4 for n in range(3) ]

在这种情况下,对每个 n 进行重新评估该表达式,从而导致不同的列表。

Actually, this is exactly what you would expect. Let's decompose what is happening here:

You write

lst = [[1] * 4] * 3

This is equivalent to:

lst1 = [1]*4
lst = [lst1]*3

This means lst is a list with 3 elements all pointing to lst1. This means the two following lines are equivalent:

lst[0][0] = 5
lst1[0] = 5

As lst[0] is nothing but lst1.

To obtain the desired behavior, you can use a list comprehension:

lst = [ [1]*4 for n in range(3) ]

In this case, the expression is re-evaluated for each n, leading to a different list.

記柔刀 2025-01-29 03:35:55
[[1] * 4] * 3

甚至:

[[1, 1, 1, 1]] * 3

创建一个列表,该列表引用内部 [1,1,1,1] 3次 - 不是内部列表的三个副本,因此每当您修改列表(在任何位置),您会看到更改三遍。

它与此示例相同:

>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

其中可能有点令人惊讶。

[[1] * 4] * 3

or even:

[[1, 1, 1, 1]] * 3

Creates a list that references the internal [1,1,1,1] 3 times - not three copies of the inner list, so any time you modify the list (in any position), you'll see the change three times.

It's the same as this example:

>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

where it's probably a little less surprising.

神仙妹妹 2025-01-29 03:35:55

my_list = [[1] * 4] * 3 在内存中创建一个列表对象 [1,1,1,1] ,并在3次之上复制其参考文献。这相当于 obj = [1,1,1,1]; my_list = [obj]*3 obj 的任何修改都将在列表中引用 obj 的三个地方反映。
正确的语句是:

my_list = [[1]*4 for _ in range(3)]

my_list = [[1 for __ in range(4)] for _ in range(3)]

在这里要注意的重要事情*操作员主要是用于创建文字列表的 。尽管 1 是不可变的,但 obj = [1]*4 仍然会创建 1 重复4次以上的列表,以形式 [ 1,1,1,1] 。但是,如果提到了一个不变的对象,则该对象被新的对象覆盖。

这意味着,如果我们做 obj [1] = 42 ,那么 obj 将成为 [1,42,1,1] not [42,42,42,42] 正如某些人可能假设的。这也可以验证:

>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # Same as my_list[0]
4522139440

>>> my_list[1] = 42  # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # id changed
4522140752
>>> id(my_list[2])  # id still same as my_list[0], still referring to value `1`.
4522139440

my_list = [[1]*4] * 3 creates one list object [1,1,1,1] in memory and copies its reference 3 times over. This is equivalent to obj = [1,1,1,1]; my_list = [obj]*3. Any modification to obj will be reflected at three places, wherever obj is referenced in the list.
The right statement would be:

my_list = [[1]*4 for _ in range(3)]

or

my_list = [[1 for __ in range(4)] for _ in range(3)]

Important thing to note here is that the * operator is mostly used to create a list of literals. Although 1 is immutable, obj = [1]*4 will still create a list of 1 repeated 4 times over to form [1,1,1,1]. But if any reference to an immutable object is made, the object is overwritten with a new one.

This means if we do obj[1] = 42, then obj will become [1,42,1,1] not [42,42,42,42] as some may assume. This can also be verified:

>>> my_list = [1]*4
>>> my_list
[1, 1, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # Same as my_list[0]
4522139440

>>> my_list[1] = 42  # Since my_list[1] is immutable, this operation overwrites my_list[1] with a new object changing its id.
>>> my_list
[1, 42, 1, 1]

>>> id(my_list[0])
4522139440
>>> id(my_list[1])  # id changed
4522140752
>>> id(my_list[2])  # id still same as my_list[0], still referring to value `1`.
4522139440
淡莣 2025-01-29 03:35:55

除了正确解释问题的接受答案外,而不是使用以下代码创建具有重复元素的列表:

[[1]*4 for _ in range(3)]

另外,您可以使用 itertools.repeat() 创建重复元素的迭代对象:

>>> a = list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0] = 5
>>> a
[5, 1, 1, 1]

如果您使用numpy,并且只想创建一个您可以使用代码> > 和/或其他数字使用 .repeat

>>> import numpy as np
>>> np.ones(4)
array([1., 1., 1., 1.])
>>> np.ones((4, 2))
array([[1., 1.],
       [1., 1.],
       [1., 1.],
       [1., 1.]])
>>> np.zeros((4, 2))
array([[0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.]])
>>> np.repeat([7], 10)
array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])

Alongside the accepted answer that explained the problem correctly, instead of creating a list with duplicated elements using following code:

[[1]*4 for _ in range(3)]

Also, you can use itertools.repeat() to create an iterator object of repeated elements:

>>> a = list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0] = 5
>>> a
[5, 1, 1, 1]

P.S. If you're using NumPy and you only want to create an array of ones or zeroes you can use np.ones and np.zeros and/or for other numbers use np.repeat:

>>> import numpy as np
>>> np.ones(4)
array([1., 1., 1., 1.])
>>> np.ones((4, 2))
array([[1., 1.],
       [1., 1.],
       [1., 1.],
       [1., 1.]])
>>> np.zeros((4, 2))
array([[0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.]])
>>> np.repeat([7], 10)
array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])
难理解 2025-01-29 03:35:55

Python容器包含对其他对象的引用。请参阅此示例:

>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]

在此 B 中,它包含一个参考列表 a 的项目。列表 a 是可变的。

列表乘以整数的乘法等同于多次添加列表(请参阅常见序列操作)。因此,继续进行以下示例:

>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]

我们可以看到列表 c 现在包含两个引用列表 a ,等效于 c = b * 2

Python FAQ还包含了这种行为的解释:

Python containers contain references to other objects. See this example:

>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]

In this b is a list that contains one item that is a reference to list a. The list a is mutable.

The multiplication of a list by an integer is equivalent to adding the list to itself multiple times (see common sequence operations). So continuing with the example:

>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]

We can see that the list c now contains two references to list a which is equivalent to c = b * 2.

Python FAQ also contains explanation of this behavior: How do I create a multidimensional list?

玻璃人 2025-01-29 03:35:55

我正在添加答案,以图解相同的解释。

您创建2D的方式,创建浅列表

arr = [[0]*cols]*row

,如果要更新列表的元素,则应使用

rows, cols = (5, 5) 
arr = [[0 for i in range(cols)] for j in range(rows)] 

说明

创建列表

arr = [0]*N 

一个人可以使用以下

arr = [0 for i in range(N)] 

方式 阵列的索引指向相同的整数对象

”在此处输入图像描述”

当您将值分配给特定索引时,创建了一个新的int对象,例如 arr [4] = 5 创建

“

现在让我们看看当我们创建列表列表列表时会发生什么,在这种情况下,我们的顶部列表的所有元素都将指向同一列表

i.sstatic.net/oicywl.png“ rel =“ nofollow noreferrer 如果更新任何索引的值,将创建新的INT对象。但是,由于所有顶级列表索引都指向同一列表,因此所有行看起来都一样。您会感觉到更新元素正在更新该列中的所有元素。

信用:感谢对于简单的解释在这里/a>

I am adding my answer to explain the same diagrammatically.

The way you created the 2D, creates a shallow list

arr = [[0]*cols]*row

Instead, if you want to update the elements of the list, you should use

rows, cols = (5, 5) 
arr = [[0 for i in range(cols)] for j in range(rows)] 

Explanation:

One can create a list using:

arr = [0]*N 

or

arr = [0 for i in range(N)] 

In the first case all the indices of the array point to the same integer object

enter image description here

and when you assign a value to a particular index, a new int object is created, for example arr[4] = 5 creates

enter image description here

Now let us see what happens when we create a list of list, in this case, all the elements of our top list will point to the same list

enter image description here

And if you update the value of any index a new int object will be created. But since all the top-level list indexes are pointing at the same list, all the rows will look the same. And you will get the feeling that updating an element is updating all the elements in that column.

enter image description here

Credits: Thanks to Pranav Devarakonda for the easy explanation here

Hello爱情风 2025-01-29 03:35:55

让我们以下面的方式重写您的代码:

x = 1
y = [x]
z = y * 4

my_list = [z] * 3

然后将其运行以下代码以使所有内容更加清晰。该代码的作用基本上是打印 id> id> id> id

返回对象的“身份”

,并将帮助我们识别它们并分析发生的事情:

print("my_list:")
for i, sub_list in enumerate(my_list):
    print("\t[{}]: {}".format(i, id(sub_list)))
    for j, elem in enumerate(sub_list):
        print("\t\t[{}]: {}".format(j, id(elem)))

您将获得以下输出:

x: 1
y: [1]
z: [1, 1, 1, 1]
my_list:
    [0]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [1]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [2]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528

因此,现在让我们逐步进行。您有 x 1 ,一个元素列表 y 包含 x 。您的第一步是 y * 4 ,它将为您提供一个新列表 z ,它基本上是 [x,x,x,x,x,x] ,即,它创建了一个新列表,该列表将具有4个元素,它是对初始 x 对象的引用。下一步非常相似。您基本上是做 z * 3 ,它是 [[x,x,x,x,x]] * 3 和返回 [[x,x,x,x,x,x,x ],[x,x,x,x],[x,x,x,x]] ,出于与第一步相同的原因。

Let's rewrite your code in the following way:

x = 1
y = [x]
z = y * 4

my_list = [z] * 3

Then having this, run the following code to make everything more clear. What the code does is basically print the ids of the obtained objects, which

Return[s] the “identity” of an object

and will help us identify them and analyse what happens:

print("my_list:")
for i, sub_list in enumerate(my_list):
    print("\t[{}]: {}".format(i, id(sub_list)))
    for j, elem in enumerate(sub_list):
        print("\t\t[{}]: {}".format(j, id(elem)))

And you will get the following output:

x: 1
y: [1]
z: [1, 1, 1, 1]
my_list:
    [0]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [1]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [2]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528

So now let's go step-by-step. You have x which is 1, and a single element list y containing x. Your first step is y * 4 which will get you a new list z, which is basically [x, x, x, x], i.e. it creates a new list which will have 4 elements, which are references to the initial x object. The next step is pretty similar. You basically do z * 3, which is [[x, x, x, x]] * 3 and returns [[x, x, x, x], [x, x, x, x], [x, x, x, x]], for the same reason as for the first step.

一束光,穿透我孤独的魂 2025-01-29 03:35:55

简单地说,这是因为在Python中,一切都可以通过参考来工作,因此,当您创建以这种方式创建列表时,您基本上会遇到此类问题。

要解决您的问题,您可以做一个:

  1. 使用numpy数组; numpy.empty.empty
  2. 列表时,您可以进入列表。
  3. 如果需要,也可以使用字典

In simple words this is happening because in python everything works by reference, so when you create a list of list that way you basically end up with such problems.

To solve your issue you can do either one of them:

  1. Use numpy array; documentation for numpy.empty
  2. Append the list as you get to a list.
  3. You can also use dictionary if you want
哭泣的笑容 2025-01-29 03:35:55

每个人都在解释正在发生的事情。我会建议一种解决它的方法:

my_list = [[1 for i in range(4)] for j in range(3)]

my_list[0][0] = 5
print(my_list)

然后您得到:

[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

Everyone is explaining what is happening. I'll suggest one way to solve it:

my_list = [[1 for i in range(4)] for j in range(3)]

my_list[0][0] = 5
print(my_list)

And then you get:

[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
避讳 2025-01-29 03:35:55

@spelchekr来自 python list list list乘法:[[[ [...]]*3列出3个列表,在修改时互相镜像,我也有同样的问题
“为什么只有外部*3 在内部没有的情况下创建更多的引用?为什么不是全部1s?”

li = [0] * 3
print([id(v) for v in li])  # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li])  # [140724141863760, 140724141863728, 140724141863728]
print(id(0))  # 140724141863728
print(id(1))  # 140724141863760
print(li)     # [1, 0, 0]

ma = [[0]*3] * 3  # mainly discuss inner & outer *3 here
print([id(li) for li in ma])  # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma])  # [1987013355080, 1987013355080, 1987013355080]
print(ma)  # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

这是尝试上述代码后的解释:

  • 内部*3 也会创建参考,但其引用是不变的,类似于 [&amp; 0,&amp; 0,&amp; 0] < /code>,然后,当您更改 li [0] 时,您无法更改const int 0 的任何基础参考,因此您只需将参考地址更改为新的一个&amp; 1 ;
  • ma = [&amp; li,&amp; li,&amp; li] li 是可变的,因此当您调用 ma [0] [0] [0] =时, 1 ma [0] [0] 等于&amp; li [0] ,因此所有&amp; li 实例将将其第一个地址更改为&amp; 1

@spelchekr from Python list multiplication: [[...]]*3 makes 3 lists which mirror each other when modified and I had the same question about
"Why does only the outer *3 create more references while the inner one doesn't? Why isn't it all 1s?"

li = [0] * 3
print([id(v) for v in li])  # [140724141863728, 140724141863728, 140724141863728]
li[0] = 1
print([id(v) for v in li])  # [140724141863760, 140724141863728, 140724141863728]
print(id(0))  # 140724141863728
print(id(1))  # 140724141863760
print(li)     # [1, 0, 0]

ma = [[0]*3] * 3  # mainly discuss inner & outer *3 here
print([id(li) for li in ma])  # [1987013355080, 1987013355080, 1987013355080]
ma[0][0] = 1
print([id(li) for li in ma])  # [1987013355080, 1987013355080, 1987013355080]
print(ma)  # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

Here is my explanation after trying the code above:

  • The inner *3 also creates references, but its references are immutable, something like [&0, &0, &0], then when you change li[0], you can't change any underlying reference of const int 0, so you can just change the reference address into the new one &1;
  • while ma = [&li, &li, &li] and li is mutable, so when you call ma[0][0] = 1, ma[0][0] is equal to &li[0], so all the &li instances will change its 1st address into &1.
記憶穿過時間隧道 2025-01-29 03:35:55

尝试更描述性地解释它,

操作1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

操作2:

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

注意到为什么不修改第一个列表的第一个元素没有修改每个列表的第二个元素?那是因为 [0] * 2 确实是两个数字的列表,而对0的引用无法修改。

如果要创建克隆副本,请尝试操作3:

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

创建克隆副本的另一种有趣方法,操作4:

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]

Trying to explain it more descriptively,

Operation 1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

Operation 2:

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

Noticed why doesn't modifying the first element of the first list didn't modify the second element of each list? That's because [0] * 2 really is a list of two numbers, and a reference to 0 cannot be modified.

If you want to create clone copies, try Operation 3:

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

another interesting way to create clone copies, Operation 4:

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
终弃我 2025-01-29 03:35:55

通过使用内置列表函数,您可以这样做

a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list

a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number

a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting

a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list

By using the inbuilt list function you can do like this

a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list

a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number

a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting

a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list
2025-01-29 03:35:55

来自

请注意
序列 s 未复制;他们被多次引用。
这常常困扰着新的Python程序员;考虑::

 &gt;&gt;&gt;列表= [[] * 3
  &gt;&gt;&gt;列表
  [[],[],[]]
  &gt;&gt;&gt;列表[0] .append(3)
  &gt;&gt;&gt;列表
  [[3],[3],[3]
 

发生的事情是 [[]] 是一个单元素列表,包含
一个空列表,因此 [[]] * 3 的所有三个元素均为参考
到这个单个空列表。修改任何元素
列表修改此单一列表。您可以创建一个清单
这种方式的不同列表::

 &gt;&gt;&gt; lists = [[]在范围(3)中为i]
  &gt;&gt;&gt;列表[0] .append(3)
  &gt;&gt;&gt;列表[1] .append(5)
  &gt;&gt;&gt;列表[2]。申请(7)
  &gt;&gt;&gt;列表
  [[3],[5],[7]]
 

From official documentation:

Note that items in the
sequence s are not copied; they are referenced multiple times.
This often haunts new Python programmers; consider::

  >>> lists = [[]] * 3
  >>> lists
  [[], [], []]
  >>> lists[0].append(3)
  >>> lists
  [[3], [3], [3]]

What has happened is that [[]] is a one-element list containing
an empty list, so all three elements of [[]] * 3 are references
to this single empty list. Modifying any of the elements of
lists modifies this single list. You can create a list of
different lists this way::

  >>> lists = [[] for i in range(3)]
  >>> lists[0].append(3)
  >>> lists[1].append(5)
  >>> lists[2].append(7)
  >>> lists
  [[3], [5], [7]]
意中人 2025-01-29 03:35:55

我到达这里是因为我想看看如何嵌套任意数量的列表。上面有很多解释和具体示例,但是您可以概括n维列表的n维列表,其中包括以下递归函数:

import copy

def list_ndim(dim, el=None, init=None):
    if init is None:
        init = el

    if len(dim)> 1:
        return list_ndim(dim[0:-1], None, [copy.copy(init) for x in range(dim[-1])])

    return [copy.deepcopy(init) for x in range(dim[0])]

您将第一个调用到这样的函数:

dim = (3,5,2)
el = 1.0
l = list_ndim(dim, el)

where (3,3,3, 5,2)是结构尺寸的元组(类似于numpy shape 参数),而 1.0 是您希望结构为的元素初始化(也无效)。请注意, init 参数仅由递归呼叫提供,以携带

上述嵌套子列表的输出:

[[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]]

集合特定元素:

l[1][3][1] = 56
l[2][2][0] = 36.0+0.0j
l[0][1][0] = 'abc'

结果输出:

[[[1.0, 1.0], ['abc', 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 56.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [(36+0j), 1.0], [1.0, 1.0], [1.0, 1.0]]]

上面证明了列表的不符合性质

I arrived here because I was looking to see how I could nest an arbitrary number of lists. There are a lot of explanations and specific examples above, but you can generalize N dimensional list of lists of lists of ... with the following recursive function:

import copy

def list_ndim(dim, el=None, init=None):
    if init is None:
        init = el

    if len(dim)> 1:
        return list_ndim(dim[0:-1], None, [copy.copy(init) for x in range(dim[-1])])

    return [copy.deepcopy(init) for x in range(dim[0])]

You make your first call to the function like this:

dim = (3,5,2)
el = 1.0
l = list_ndim(dim, el)

where (3,5,2) is a tuple of the dimensions of the structure (similar to numpy shape argument), and 1.0 is the element you want the structure to be initialized with (works with None as well). Note that the init argument is only provided by the recursive call to carry forward the nested child lists

output of above:

[[[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]]]

set specific elements:

l[1][3][1] = 56
l[2][2][0] = 36.0+0.0j
l[0][1][0] = 'abc'

resulting output:

[[[1.0, 1.0], ['abc', 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [1.0, 1.0], [1.0, 56.0], [1.0, 1.0]],
 [[1.0, 1.0], [1.0, 1.0], [(36+0j), 1.0], [1.0, 1.0], [1.0, 1.0]]]

the non-typed nature of lists is demonstrated above

她比我温柔 2025-01-29 03:35:55

尽管原始问题用乘法运算符构建了 sublist ,但我将添加一个示例,该示例使用相同的列表为sublists使用。添加此答案以使其完整性,因为此问题通常用作问题的规范,

node_count = 4
colors = [0,1,2,3]
sol_dict = {node:colors for node in range(0,node_count)}

每个字典值中的列表是同一对象,试图更改其中一个词典值。

>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> [v is colors for v in sol_dict.values()]
[True, True, True, True]
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 2, 3], 2: [0, 2, 3], 3: [0, 2, 3]}

构建字典的正确方法是为每个值使用列表的副本。

>>> colors = [0,1,2,3]
>>> sol_dict = {node:colors[:] for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}

While the original question constructed the sublists with the multiplication operator, I'll add an example that uses the same list for the sublists. Adding this answer for completeness as this question is often used as a canonical for the issue

node_count = 4
colors = [0,1,2,3]
sol_dict = {node:colors for node in range(0,node_count)}

The list in each dictionary value is the same object, trying to change one of the dictionaries values will be seen in all.

>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> [v is colors for v in sol_dict.values()]
[True, True, True, True]
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 2, 3], 2: [0, 2, 3], 3: [0, 2, 3]}

The correct way to construct the dictionary would be to use a copy of the list for each value.

>>> colors = [0,1,2,3]
>>> sol_dict = {node:colors[:] for node in range(0,node_count)}
>>> sol_dict
{0: [0, 1, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
>>> sol_dict[0].remove(1)
>>> sol_dict
{0: [0, 2, 3], 1: [0, 1, 2, 3], 2: [0, 1, 2, 3], 3: [0, 1, 2, 3]}
春夜浅 2025-01-29 03:35:55

请注意,序列中的项目未复制;他们被多次引用。这常常困扰着新的Python程序员;考虑:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]

发生的事情是 [[] 是包含空列表的单元素列表,因此 [[]] * 3 的所有三个元素均为引用到这个单个空列表。修改列表的任何元素都会修改此列表。

解释这一点的另一个示例是使用多维数组

您可能尝试制作一个多维数组:

>>> A = [[None] * 2] * 3

如果您打印它,则看起来正确:

>>> A
[[None, None], [None, None], [None, None]]

但是当您分配一个值时,它在多个位置显示:

>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]

原因是使用&nbsp; *复制列表。 &nbsp;不创建副本,而仅创建对现有对象的引用。 3&nbsp;创建了一个包含3个引用的列表,列出了相同的长度列表。一行的更改将在所有行中显示,这几乎可以肯定不是您想要的。

Note that items in the sequence are not copied; they are referenced multiple times. This often haunts new Python programmers; consider:

>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]

What has happened is that [[]] is a one-element list containing an empty list, so all three elements of [[]] * 3 are references to this single empty list. Modifying any of the elements of lists modifies this single list.

Another example to explain this is using multi-dimensional arrays.

You probably tried to make a multidimensional array like this:

>>> A = [[None] * 2] * 3

This looks correct if you print it:

>>> A
[[None, None], [None, None], [None, None]]

But when you assign a value, it shows up in multiple places:

>>> A[0][0] = 5
>>> A
[[5, None], [5, None], [5, None]]

The reason is that replicating a list with * doesn’t create copies, it only creates references to the existing objects. The 3 creates a list containing 3 references to the same list of length two. Changes to one row will show in all rows, which is almost certainly not what you want.

晚风撩人 2025-01-29 03:35:55

每个子列表的每个第一个元素都更改为5,因为“ XS”具有相同的列表3次,数据正在共享。打印并未显示以下内容,但使用:

https://pypi.org/project/project/memory-graph/memory-graph/

您可以画出数据并轻松查看:

import memory_graph as mg # see install instructions at link above

xs = [[1] * 4] * 3
print(xs)
xs[0][0] = 5
print(xs)

mg.show(locals(), block=True) # draw graph

import memory_graph as mg

xs = [[1] * 4 for _ in range(3)] # <----- list comprehension
print(xs)
xs[0][0] = 5
print(xs)

mg.show(locals(), block=True)

​ ”>

sstatic.net/jpnfo.png“ rel =“ nofollow noreferrer :

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

全面披露:我是 memory_graph 的开发人员。

Every first element of each sublist changed to 5 because 'xs' has the same list three times, the data is being shared. Printing doesn't show this but using:

https://pypi.org/project/memory-graph/

you can graph your data and see this easily:

import memory_graph as mg # see install instructions at link above

xs = [[1] * 4] * 3
print(xs)
xs[0][0] = 5
print(xs)

mg.show(locals(), block=True) # draw graph

enter image description here

Instead you probably want to use a list comprehension so that the data is not shared:

import memory_graph as mg

xs = [[1] * 4 for _ in range(3)] # <----- list comprehension
print(xs)
xs[0][0] = 5
print(xs)

mg.show(locals(), block=True)

enter image description here

Which gives output:

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

Full disclosure: I am the developer of memory_graph.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文