列表的列表更改出人意料地反映了
我创建了一个列表:
>>> 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
?
另请参阅:
- /stackoverflow.com/questions/46835197">字典商店的清单仅在每种迭代中最后一个附加的值
-
如何初始化python中的空列表字典?对于一个类似的问题,与列表的列表有关
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
@spelchekr来自 python list list list乘法:[[[ [...]]*3列出3个列表,在修改时互相镜像,我也有同样的问题
“为什么只有外部
*3
在内部没有的情况下创建更多的引用?为什么不是全部1s?”这是尝试上述代码后的解释:
*3
也会创建参考,但其引用是不变的,类似于[&amp; 0,&amp; 0,&amp; 0] < /code>,然后,当您更改
li [0]
时,您无法更改const int0
的任何基础参考,因此您只需将参考地址更改为新的一个&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?"Here is my explanation after trying the code above:
*3
also creates references, but its references are immutable, something like[&0, &0, &0]
, then when you changeli[0]
, you can't change any underlying reference of const int0
, so you can just change the reference address into the new one&1
;ma = [&li, &li, &li]
andli
is mutable, so when you callma[0][0] = 1
,ma[0][0]
is equal to&li[0]
, so all the&li
instances will change its 1st address into&1
.尝试更描述性地解释它,
操作1:
操作2:
注意到为什么不修改第一个列表的第一个元素没有修改每个列表的第二个元素?那是因为
[0] * 2
确实是两个数字的列表,而对0的引用无法修改。如果要创建克隆副本,请尝试操作3:
创建克隆副本的另一种有趣方法,操作4:
Trying to explain it more descriptively,
Operation 1:
Operation 2:
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:
another interesting way to create clone copies, Operation 4:
通过使用内置列表函数,您可以这样做
By using the inbuilt list function you can do like this
来自
From official documentation:
我到达这里是因为我想看看如何嵌套任意数量的列表。上面有很多解释和具体示例,但是您可以概括n维列表的n维列表,其中包括以下递归函数:
您将第一个调用到这样的函数:
where
(3,3,3, 5,2)
是结构尺寸的元组(类似于numpyshape
参数),而1.0
是您希望结构为的元素初始化(也无效)。请注意,init
参数仅由递归呼叫提供,以携带上述嵌套子列表的输出:
集合特定元素:
结果输出:
上面证明了列表的不符合性质
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:
You make your first call to the function like this:
where
(3,5,2)
is a tuple of the dimensions of the structure (similar to numpyshape
argument), and1.0
is the element you want the structure to be initialized with (works with None as well). Note that theinit
argument is only provided by the recursive call to carry forward the nested child listsoutput of above:
set specific elements:
resulting output:
the non-typed nature of lists is demonstrated above
尽管原始问题用乘法运算符构建了 sublist ,但我将添加一个示例,该示例使用相同的列表为sublists使用。添加此答案以使其完整性,因为此问题通常用作问题的规范,
每个字典值中的列表是同一对象,试图更改其中一个词典值。
构建字典的正确方法是为每个值使用列表的副本。
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
The list in each dictionary value is the same object, trying to change one of the dictionaries values will be seen in all.
The correct way to construct the dictionary would be to use a copy of the list for each value.
请注意,序列中的项目未复制;他们被多次引用。这常常困扰着新的Python程序员;考虑:
发生的事情是
[[]
是包含空列表的单元素列表,因此[[]] * 3
的所有三个元素均为引用到这个单个空列表。修改列表的任何元素都会修改此列表。解释这一点的另一个示例是使用多维数组。
您可能尝试制作一个多维数组:
如果您打印它,则看起来正确:
但是当您分配一个值时,它在多个位置显示:
原因是使用&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:
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:
This looks correct if you print it:
But when you assign a value, it shows up in multiple places:
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.每个子列表的每个第一个元素都更改为5,因为“ XS”具有相同的列表3次,数据正在共享。打印并未显示以下内容,但使用:
https://pypi.org/project/project/memory-graph/memory-graph/
您可以画出数据并轻松查看:
”>
sstatic.net/jpnfo.png“ rel =“ nofollow noreferrer :
全面披露:我是 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:
Instead you probably want to use a list comprehension so that the data is not shared:
Which gives output:
Full disclosure: I am the developer of memory_graph.
当您编写
[X]*3
时,您可以获得列表[x,x,x]
。也就是说,一个对相同x
的参考的列表。然后,当您修改此单个X
时,可以通过所有三个引用可见:要修复它,您需要确保在每个位置上创建一个新列表。一种方法是
每次将重新评估
[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 samex
. When you then modify this singlex
it is visible via all three references to it:To fix it, you need to make sure that you create a new list at each position. One way to do it is
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)]
reevaluatesx**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 like1.value = 2
and turn a 1 into a 2.< %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:
Live visualization using Python Tutor:
实际上,这正是您所期望的。让我们分解此处发生的事情:
您编写的
等同于:
这意味着
lst
是一个指向lst1
的列表。这意味着以下两个行是等效的:AS
lst [0]
不过是lst1
。为了获得所需的行为,您可以使用列表理解:
在这种情况下,对每个
n
进行重新评估该表达式,从而导致不同的列表。Actually, this is exactly what you would expect. Let's decompose what is happening here:
You write
This is equivalent to:
This means
lst
is a list with 3 elements all pointing tolst1
. This means the two following lines are equivalent:As
lst[0]
is nothing butlst1
.To obtain the desired behavior, you can use a list comprehension:
In this case, the expression is re-evaluated for each
n
, leading to a different list.甚至:
创建一个列表,该列表引用内部
[1,1,1,1]
3次 - 不是内部列表的三个副本,因此每当您修改列表(在任何位置),您会看到更改三遍。它与此示例相同:
其中可能有点令人惊讶。
or even:
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:
where it's probably a little less surprising.
my_list = [[1] * 4] * 3
在内存中创建一个列表对象[1,1,1,1]
,并在3次之上复制其参考文献。这相当于obj = [1,1,1,1]; my_list = [obj]*3
。obj
的任何修改都将在列表中引用obj
的三个地方反映。正确的语句是:
或
在这里要注意的重要事情是
*
操作员主要是用于创建文字列表的 。尽管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] * 3
creates one list object[1,1,1,1]
in memory and copies its reference 3 times over. This is equivalent toobj = [1,1,1,1]; my_list = [obj]*3
. Any modification toobj
will be reflected at three places, whereverobj
is referenced in the list.The right statement would be:
or
Important thing to note here is that the
*
operator is mostly used to create a list of literals. Although1
is immutable,obj = [1]*4
will still create a list of1
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
, thenobj
will become[1,42,1,1]
notas some may assume. This can also be verified:[42,42,42,42]
除了正确解释问题的接受答案外,而不是使用以下代码创建具有重复元素的列表:
另外,您可以使用
itertools.repeat()
创建重复元素的迭代对象:如果您使用numpy,并且只想创建一个您可以使用代码> 和 > 和/或其他数字使用 .repeat :
Alongside the accepted answer that explained the problem correctly, instead of creating a list with duplicated elements using following code:
Also, you can use
itertools.repeat()
to create an iterator object of repeated elements:P.S. If you're using NumPy and you only want to create an array of ones or zeroes you can use
np.ones
andnp.zeros
and/or for other numbers usenp.repeat
:Python容器包含对其他对象的引用。请参阅此示例:
在此
B
中,它包含一个参考列表a
的项目。列表a
是可变的。列表乘以整数的乘法等同于多次添加列表(请参阅常见序列操作)。因此,继续进行以下示例:
我们可以看到列表
c
现在包含两个引用列表a
,等效于c = b * 2
。Python FAQ还包含了这种行为的解释:
Python containers contain references to other objects. See this example:
In this
b
is a list that contains one item that is a reference to lista
. The lista
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:
We can see that the list
c
now contains two references to lista
which is equivalent toc = b * 2
.Python FAQ also contains explanation of this behavior: How do I create a multidimensional list?
我正在添加答案,以图解相同的解释。
您创建2D的方式,创建浅列表
,如果要更新列表的元素,则应使用
说明:
创建列表
一个人可以使用以下
方式 阵列的索引指向相同的整数对象
当您将值分配给特定索引时,创建了一个新的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
Instead, if you want to update the elements of the list, you should use
Explanation:
One can create a list using:
or
In the first case all the indices of the array point to the same integer object
and when you assign a value to a particular index, a new int object is created, for example
arr[4] = 5
createsNow 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
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.
Credits: Thanks to Pranav Devarakonda for the easy explanation here
让我们以下面的方式重写您的代码:
然后将其运行以下代码以使所有内容更加清晰。该代码的作用基本上是打印
id> id> id> id
,并将帮助我们识别它们并分析发生的事情:
您将获得以下输出:
因此,现在让我们逐步进行。您有
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:
Then having this, run the following code to make everything more clear. What the code does is basically print the
id
s of the obtained objects, whichand will help us identify them and analyse what happens:
And you will get the following output:
So now let's go step-by-step. You have
x
which is1
, and a single element listy
containingx
. Your first step isy * 4
which will get you a new listz
, which is basically[x, x, x, x]
, i.e. it creates a new list which will have 4 elements, which are references to the initialx
object. The next step is pretty similar. You basically doz * 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.简单地说,这是因为在Python中,一切都可以通过参考来工作,因此,当您创建以这种方式创建列表时,您基本上会遇到此类问题。
要解决您的问题,您可以做一个:
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:
每个人都在解释正在发生的事情。我会建议一种解决它的方法:
然后您得到:
Everyone is explaining what is happening. I'll suggest one way to solve it:
And then you get: