我如何克隆列表,以免在分配后意外变化?
在使用 new_list = my_list
时,对 new_list
更改 my_list
每次的任何修改。为什么这是这样,如何克隆或复制列表以防止它?例如:
>>> my_list = [1, 2, 3]
>>> new_list = my_list
>>> new_list.append(4)
>>> my_list
[1, 2, 3, 4]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(25)
new_list = my_list
实际上并未创建第二个列表。分配仅复制对列表的引用,而不是实际列表,因此new_list
和my_list
在分配后请参阅同一列表。要实际复制列表,您有几个选项:
您可以使用https://docs.python.org/library/stdtypes.html#mutable-sequence-sequence-types“ rel = “ noreferrer”>
list.copy()
方法(自Python 3.3以来可用):您可以切片:
alex martelli 的观点(至少。 ;)(他认为,下一个更可读)。
您可以使用内置 list() < < /a>构造函数:
您可以使用通用“ noreferrer”>
copy> copy.copy.copy.copy()
:
这比
list()
要慢一点,因为它必须找出old_list
首先的数据类型。如果您还需要复制列表的元素,请使用通用 <代码> copy.deepcopy() :
显然是最慢,最有必要的方法,但有时不可避免。这是递归运作的;它将处理任意数量的嵌套列表(或其他容器)。
示例:
结果:
new_list = my_list
doesn't actually create a second list. The assignment just copies the reference to the list, not the actual list, so bothnew_list
andmy_list
refer to the same list after the assignment.To actually copy the list, you have several options:
You can use the built-in
list.copy()
method (available since Python 3.3):You can slice it:
Alex Martelli's opinion (at least back in 2007) about this is, that it is a weird syntax and it does not make sense to use it ever. ;) (In his opinion, the next one is more readable).
You can use the built-in
list()
constructor:You can use generic
copy.copy()
:This is a little slower than
list()
because it has to find out the datatype ofold_list
first.If you need to copy the elements of the list as well, use generic
copy.deepcopy()
:Obviously the slowest and most memory-needing method, but sometimes unavoidable. This operates recursively; it will handle any number of levels of nested lists (or other containers).
Example:
Result:
Felix已经提供了一个很好的答案,但是我认为我会对各种方法进行速度比较:
copy.deepcopy(old_list)
copy> copy> copy> copy()
>方法与DeepCopy复制类copy> copy()
方法不复制类(仅dicts/lists/tarples)>对于old_list中的项目:new_list.append(item)
[i in old_list]
(anew_list = []; new_list.extend(old_list)
old_list [:]
(列表切片),因此最快的是列表切片。但是请注意,
copy.copy()
,list [:]
和list(list)
,不同, copy> copy.deepcopy() 和Python版本不会复制列表中的任何列表,字典和类实例,因此,如果原始内容更改,它们也会在复制列表中更改,反之亦然。(如果有人有兴趣或想提出任何问题,这是脚本:)
Felix already provided an excellent answer, but I thought I'd do a speed comparison of the various methods:
copy.deepcopy(old_list)
Copy()
method copying classes with deepcopyCopy()
method not copying classes (only dicts/lists/tuples)for item in old_list: new_list.append(item)
[i for i in old_list]
(a list comprehension)copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
old_list[:]
(list slicing)So the fastest is list slicing. But be aware that
copy.copy()
,list[:]
andlist(list)
, unlikecopy.deepcopy()
and the python version don't copy any lists, dictionaries and class instances in the list, so if the originals change, they will change in the copied list too and vice versa.(Here's the script if anyone's interested or wants to raise any issues:)
我被告知 href =“ http://bugs.python.org/issue10516” rel =“ noreferrer”>添加
list.copy.copy()
方法,该方法应该像切片一样快:I've been told that Python 3.3+ adds the
list.copy()
method, which should be as fast as slicing:在Python 3中,可以使用:
在Python 2和3中进行浅副本,您可以获得带有原始完整切片的浅副本:
说明
有两种语义方法来复制列表。浅副本创建了相同对象的新列表,深层副本创建了一个包含新等价对象的新列表。
浅层列表复制
浅副本仅复制列表本身,该列表本身是对列表中对象的引用的容器。如果包含的对象是可变的,并且一个更改了,则更改将反映在两个列表中。
在Python 2和3中有不同的方法可以做到这一点。Python 2方法也将在Python3。Python2
中使用Python 2
,这是制作列表浅副本的惯用方法,其原始作品的完整切片:
您还可以通过通过列表构造函数将列表传递到构造函数,
但是使用构造函数效率较低:
Python 3中的Python 3
,列表在
list.copy.copy.copy
方法:python 3.5:
制作:制作 :另一个指针确实不是制作副本
my_list
只是指向内存中实际列表的名称。当您说new_list = my_list
您没有制作副本时,您只是在内存中添加了另一个名称。当我们制作清单副本时,我们可能会遇到类似的问题。该列表只是内容的一系列指针,因此浅副本仅复制指针,因此您有两个不同的列表,但是它们具有相同的内容。为了制作内容的副本,您需要深层副本。
深副本
以使a 列表的深副本,在Python 2或3中,使用
deepcopy
deepcopy < /code>在
复制
模块中:
为了演示这允许我们制作新的子列表:
因此,我们看到深层复制列表与原始列表完全不同。您可以滚动自己的功能 - 但不要。您可能会通过使用标准库的DeepCopy函数来创建原本不会遇到的错误。
请勿使用
eval
您可能会将其视为DeepCopy的一种方式,但不要这样做:
在64位Python 2.7中:
在64位Python 3.5:
In Python 3, a shallow copy can be made with:
In Python 2 and 3, you can get a shallow copy with a full slice of the original:
Explanation
There are two semantic ways to copy a list. A shallow copy creates a new list of the same objects, a deep copy creates a new list containing new equivalent objects.
Shallow list copy
A shallow copy only copies the list itself, which is a container of references to the objects in the list. If the objects contained themselves are mutable and one is changed, the change will be reflected in both lists.
There are different ways to do this in Python 2 and 3. The Python 2 ways will also work in Python 3.
Python 2
In Python 2, the idiomatic way of making a shallow copy of a list is with a complete slice of the original:
You can also accomplish the same thing by passing the list through the list constructor,
but using the constructor is less efficient:
Python 3
In Python 3, lists get the
list.copy
method:In Python 3.5:
Making another pointer does not make a copy
my_list
is just a name that points to the actual list in memory. When you saynew_list = my_list
you're not making a copy, you're just adding another name that points at that original list in memory. We can have similar issues when we make copies of lists.The list is just an array of pointers to the contents, so a shallow copy just copies the pointers, and so you have two different lists, but they have the same contents. To make copies of the contents, you need a deep copy.
Deep copies
To make a deep copy of a list, in Python 2 or 3, use
deepcopy
in thecopy
module:To demonstrate how this allows us to make new sub-lists:
And so we see that the deep copied list is an entirely different list from the original. You could roll your own function - but don't. You're likely to create bugs you otherwise wouldn't have by using the standard library's deepcopy function.
Don't use
eval
You may see this used as a way to deepcopy, but don't do it:
In 64 bit Python 2.7:
on 64 bit Python 3.5:
让我们从头开始探讨这个问题。
因此,让我们假设您有两个列表:
我们必须复制两个列表,现在从第一个列表开始:
因此,首先让我们尝试将变量
复制
设置为我们的原始列表,List_1 :
现在,如果您正在考虑复制 list_1 的复制,那么您错了。
ID
函数可以向我们展示两个变量是否可以指向同一对象。让我们尝试一下:输出是:
两个变量都是完全相同的参数。你感到惊讶吗?
因此,众所周知,Python不会将任何内容存储在变量中,变量只是引用对象并将对象存储为值。这里的对象是
list
,但是我们通过两个不同的变量名称创建了两个对同一对象的引用。这意味着两个变量都指向同一对象,只是带有不同的名称。当您进行
copy = list_1
时,它实际上是在做:在图像 list_1 和 copy 中名称,但是两个变量的对象相同,即
list
。因此,如果您尝试修改复制列表,则它也会修改原始列表,因为该列表仅在那里,无论您是从复制列表或原始列表中进行的,您都会修改该列表:
输出:
因此,它修改了原始列表:
现在,让我们转到用于复制列表的Pythonic方法。
此方法修复了我们遇到的第一个问题:
因此,因为我们可以看到两个列表具有不同的ID,这意味着两个变量都指向不同的对象。因此,这里实际发生的是:
现在让我们尝试修改列表,让我们看看是否仍然遇到了先前的问题:
输出是:
如您所见,它仅修改了复制的列表。这意味着它有效。
你认为我们已经完成了吗?否。让我们尝试复制我们的嵌套列表。
List_2
应引用另一个对象,该对象是list_2
的副本。让我们检查一下:我们得到输出:
现在我们可以假设两个列表都指向不同的对象,所以现在让我们尝试对其进行修改,让我们看看它给出了我们想要的东西:
这给了我们输出:
这似乎有些混乱,因为我们以前使用过的相同方法也有效。让我们尝试理解这一点。
当您这样做时:
您只是复制外部列表,而不是内部列表。我们可以再次使用
ID
函数来检查此问题。输出是:
当我们进行
copy_2 = list_2 [:]
时,这发生了:< img src =“ https://i.sstatic.net/3hpti.jpg” alt =“在此处输入图像说明”>
它创建了列表的副本,但只有外部列表副本,而不是嵌套的列表副本。两个变量的嵌套列表相同,因此,如果您尝试修改嵌套列表,则它将修改原始列表,因为两个列表的嵌套列表对象相同。
什么是解决方案?解决方案是
deepCopy
函数。让我们检查一下:
两个外部列表都有不同的ID。让我们在内部嵌套列表上尝试一下。
输出是:
您可以看到两个ID都不同,这意味着我们可以假设两个嵌套列表现在都指向不同的对象。
这意味着当您进行
deep = deepCopy(list_2)
实际发生的事情时:两个嵌套列表都指向不同的对象,并且它们现在具有嵌套列表的单独副本。
现在,让我们尝试修改嵌套列表,看看它是否解决了上一个问题:
它输出:
如您所见,它没有修改原始嵌套列表,它仅修改了复制的列表。
Let's start from the beginning and explore this question.
So let's suppose you have two lists:
And we have to copy both lists, now starting from the first list:
So first let's try by setting the variable
copy
to our original list,list_1
:Now if you are thinking copy copied the list_1, then you are wrong. The
id
function can show us if two variables can point to the same object. Let's try this:The output is:
Both variables are the exact same argument. Are you surprised?
So as we know, Python doesn't store anything in a variable, Variables are just referencing to the object and object store the value. Here object is a
list
but we created two references to that same object by two different variable names. This means that both variables are pointing to the same object, just with different names.When you do
copy = list_1
, it is actually doing:Here in the image list_1 and copy are two variable names, but the object is same for both variable which is
list
.So if you try to modify copied list then it will modify the original list too because the list is only one there, you will modify that list no matter you do from the copied list or from the original list:
Output:
So it modified the original list:
Now let's move onto a Pythonic method for copying lists.
This method fixes the first issue we had:
So as we can see our both list having different id and it means that both variables are pointing to different objects. So what actually going on here is:
Now let's try to modify the list and let's see if we still face the previous problem:
The output is:
As you can see, it only modified the copied list. That means it worked.
Do you think we're done? No. Let's try to copy our nested list.
list_2
should reference to another object which is copy oflist_2
. Let's check:We get the output:
Now we can assume both lists are pointing different object, so now let's try to modify it and let's see it is giving what we want:
This gives us the output:
This may seem a little bit confusing, because the same method we previously used worked. Let's try to understand this.
When you do:
You're only copying the outer list, not the inside list. We can use the
id
function once again to check this.The output is:
When we do
copy_2 = list_2[:]
, this happens:It creates the copy of list, but only outer list copy, not the nested list copy. The nested list is same for both variable, so if you try to modify the nested list then it will modify the original list too as the nested list object is same for both lists.
What is the solution? The solution is the
deepcopy
function.Let's check this:
Both outer lists have different IDs. Let's try this on the inner nested lists.
The output is:
As you can see both IDs are different, meaning we can assume that both nested lists are pointing different object now.
This means when you do
deep = deepcopy(list_2)
what actually happens:Both nested lists are pointing different object and they have separate copy of nested list now.
Now let's try to modify the nested list and see if it solved the previous issue or not:
It outputs:
As you can see, it didn't modify the original nested list, it only modified the copied list.
已经有很多答案告诉您如何制作适当的副本,但是他们都没有说为什么您的原始“副本”失败了。
Python不存储变量中的值;它将名称绑定到对象。您的原始分配将
my_list
引用的对象也将其绑定到new_list
。无论您使用哪个名称,仍然只有一个列表,因此将其称为my_list
时所做的更改将在将其称为new_list
时持续。每个问题的其他答案都为您提供了创建新对象以绑定到new_list
的不同方法。列表的每个元素都像一个名称一样,因为每个元素都非限制在对象上。浅副本创建了一个新列表,其元素与以前一样绑定到相同的对象。
要使您的列表更进一步,请复制列表所指的每个对象,并将这些元素副本绑定到新列表中。
这还不是深副本,因为列表的每个元素都可以指其他对象,就像列表绑定到其元素一样。递归复制列表中的每个元素,然后相互互相复制每个元素所引用的对象,依此类推:执行深副本。
请参阅文档有关复制角色的更多信息。
There are many answers already that tell you how to make a proper copy, but none of them say why your original 'copy' failed.
Python doesn't store values in variables; it binds names to objects. Your original assignment took the object referred to by
my_list
and bound it tonew_list
as well. No matter which name you use there is still only one list, so changes made when referring to it asmy_list
will persist when referring to it asnew_list
. Each of the other answers to this question give you different ways of creating a new object to bind tonew_list
.Each element of a list acts like a name, in that each element binds non-exclusively to an object. A shallow copy creates a new list whose elements bind to the same objects as before.
To take your list copy one step further, copy each object that your list refers to, and bind those element copies to a new list.
This is not yet a deep copy, because each element of a list may refer to other objects, just like the list is bound to its elements. To recursively copy every element in the list, and then each other object referred to by each element, and so on: perform a deep copy.
See the documentation for more information about corner cases in copying.
使用
thing [:]
Use
thing[:]
Python 3.6时间
是使用Python 3.6.8的定时结果。请记住,这些时候是相对的,而不是绝对的。
我坚持只做浅副本,还添加了一些新方法,这些方法是python&nbsp; 2中不可能的,例如
list.copy.copy.copy()
(python&nbsp; 3 slice等效)和两种形式的列表解开包装(*new_list,= list
and code> new_list = [*list> list] ):我们可以请参阅Python 2获胜者仍然表现不错,但并没有大量考虑Python 3
list.copy.copy()
,尤其是考虑到后者的出色可读性。黑马是打开包装和重新包装方法(
b = [*a]
),比原始切片快25%,速度是其他解压缩方法的两倍以上(> *b,= a
)。b = a * 1
也表现出色。请注意,这些方法对除列表以外的任何输入而不是输出等效结果。它们都适用于切片对象,其中一些可用于任何觉得,但只有
复制.copy()
适用于更通用的Python对象。这是感兴趣的各方的测试代码( template” ):
Python 3.6 Timings
Here are the timing results using Python 3.6.8. Keep in mind these times are relative to one another, not absolute.
I stuck to only doing shallow copies, and also added some new methods that weren't possible in Python 2, such as
list.copy()
(the Python 3 slice equivalent) and two forms of list unpacking (*new_list, = list
andnew_list = [*list]
):We can see the Python 2 winner still does well, but doesn't edge out Python 3
list.copy()
by much, especially considering the superior readability of the latter.The dark horse is the unpacking and repacking method (
b = [*a]
), which is ~25% faster than raw slicing, and more than twice as fast as the other unpacking method (*b, = a
).b = a * 1
also does surprisingly well.Note that these methods do not output equivalent results for any input other than lists. They all work for sliceable objects, a few work for any iterable, but only
copy.copy()
works for more general Python objects.Here is the testing code for interested parties (Template from here):
python的习语是
newlist = oldlist [:]
Python's idiom for doing this is
newList = oldList[:]
所有其他贡献者都给出了出色答案,当您具有单个维度(级别)列表时,这些答案可起作用,但是到目前为止提到的方法,只有
copy.deepcopy()
当您使用多维的嵌套列表(列表列表)时,可以用克隆/复制列表,而没有指向嵌套的list
对象。而 felix kling 在他的答案中指的是它,问题还有更多,可能还有一个解决工具的方法内置可能证明是deepcopy
的更快替代方案。new_list = old_list [:]
,copy.copy(old_list)'
和py3kold_list.copy.copy()
为单层列表工作,他们还原为指向list
嵌套在old_list
和new_list
中的对象,并更改为list 对象在另一个中存在。
编辑:揭露新信息
正如其他人所说的那样, 使用
复制
模块和copy.deepcopy
绩效问题强>用于多维列表 。All of the other contributors gave great answers, which work when you have a single dimension (leveled) list, however of the methods mentioned so far, only
copy.deepcopy()
works to clone/copy a list and not have it point to the nestedlist
objects when you are working with multidimensional, nested lists (list of lists). While Felix Kling refers to it in his answer, there is a little bit more to the issue and possibly a workaround using built-ins that might prove a faster alternative todeepcopy
.While
new_list = old_list[:]
,copy.copy(old_list)'
and for Py3kold_list.copy()
work for single-leveled lists, they revert to pointing at thelist
objects nested within theold_list
and thenew_list
, and changes to one of thelist
objects are perpetuated in the other.Edit: New information brought to light
As others have stated, there are significant performance issues using the
copy
module andcopy.deepcopy
for multidimensional lists.令我惊讶的是,尚未提及这一点,因此为了完整的目的,
您可以执行用“ Splat Operator”打开包装的列表:
*
,它也将复制列表的元素。这种方法的明显缺点是它仅在Python 3.5+中可用。
明智的定时,这似乎比其他常见方法更好。
It surprises me that this hasn't been mentioned yet, so for the sake of completeness...
You can perform list unpacking with the "splat operator":
*
, which will also copy elements of your list.The obvious downside to this method is that it is only available in Python 3.5+.
Timing wise though, this appears to perform better than other common methods.
new_list = my_list
尝试理解这一点。假设 my_list 位于位置x,即, my_list 的位置。 '让 new_list 指向X。这被称为a 浅复制。
现在,如果您将
new_list = my_list [:]
分配,您只是将每个对象复制到 my_list new_list 。这被称为A 深拷贝。您可以做到的其他方法是:
new_list = my_list
Try to understand this. Let's say that my_list is in the heap memory at location X, i.e., my_list is pointing to the X. Now by assigning
new_list = my_list
you're letting new_list point to the X. This is known as a shallow copy.Now if you assign
new_list = my_list[:]
, you're simply copying each object of my_list to new_list. This is known as a deep copy.The other ways you can do this are:
一种非常简单的方法独立于python版本,在已经提供的答案中丢失了,您大多数时候都可以使用它(至少我这样做):
但是,如果 my_list 包含其他容器(例如,嵌套列表),您必须使用 deepcopy ,就像上述复制库中的答案中所建议的那样。例如:
。奖金:如果您不想复制元素使用(又称浅副本):
让我们理解解决方案#1和解决方案#2之间的区别
,那么解决方案#1工作#1当我们不使用嵌套列表时。让我们检查一下当我们将解决方案#1应用于嵌套列表时会发生什么。
A very simple approach independent of python version was missing in already-given answers which you can use most of the time (at least I do):
However, if my_list contains other containers (for example, nested lists) you must use deepcopy as others suggested in the answers above from the copy library. For example:
.Bonus: If you don't want to copy elements use (AKA shallow copy):
Let's understand difference between solution #1 and solution #2
As you can see, solution #1 worked perfectly when we were not using the nested lists. Let's check what will happen when we apply solution #1 to nested lists.
我想发布一些与其他答案有所不同的内容。即使这很可能不是最容易理解或最快的选择,但它提供了一些内部视图,可以很好地了解深拷贝的工作原理,并且是深层复制的另一种选择。我的功能是否有错误并不重要,因为这样做的目的是显示出一种复制诸如“问题答案”之类的对象的方法,同时也将其作为解释DeepCopy在其核心方面的工作方式。
任何深层复制功能的核心都是制作浅副本的方法。如何?简单的。任何深层复制功能都只能复制不变对象的容器。当您深入嵌套列表时,您只会复制外部列表,而不是列表内部的可变对象。您仅重复容器。上课也相同的作品。当您深入一堂课时,您会深入副本所有可变属性。那怎么?您只需要复制列表,dict,元组,迭代,课程和课堂实例之类的容器?
很简单。一个可变的对象并不能真正重复。它永远无法更改,因此它只是一个值。这意味着您永远不必复制字符串,数字,布尔或任何一个。但是,您将如何复制容器?简单的。您只需初始化一个具有所有值的新容器。深拷贝依赖于递归。它复制了所有容器,甚至在其中包含容器,直到没有容器。容器是一个不变的对象。
一旦您知道这一点,就可以完全复制一个没有任何参考的对象。这是用于深编辑基本数据类型的功能(对自定义类不起作用,但您可以始终添加)
Python自己的内置DeepCopy依靠该示例。唯一的区别是它支持其他类型,并且还通过将属性复制到新的重复类中来支持用户级,并以对对象的参考来阻止Infinite recursion,它已经使用备忘录列表或词典看到了它。这确实是为了制作深层副本。从本质上讲,制作深层副本只是制作浅副本。我希望这个答案为问题增加了一些东西。
示例
说您有此列表:
[1,2,3]
。不变的数字不能重复,但另一层可以。您可以使用列表理解来复制它:[x for x in [1,2,3]
] 4],[5,6]] 。这次,您想制作一个函数,该功能使用递归来深层复制列表的所有层。而不是上一个列表理解:
它使用新的列表来列表:
deepcopy_list 看起来像这样:
然后,您拥有一个函数,可以deepCopy strs,bools,bools,ploast,ints的任何列表甚至列表使用递归无限多层。在那里,您有它,深层复制。
tldr :DeepCopy使用递归来复制对象,并且仅返回与以前相同的不变对象,因为不可变的对象无法重复。但是,它深深地构成了可变物体的最内部层,直到到达对象的最外面可变层为止。
I wanted to post something a bit different than some of the other answers. Even though this is most likely not the most understandable, or fastest option, it provides a bit of an inside view of how deep copy works, as well as being another alternative option for deep copying. It doesn't really matter if my function has bugs, since the point of this is to show a way to copy objects like the question answers, but also to use this as a point to explain how deepcopy works at its core.
At the core of any deep copy function is way to make a shallow copy. How? Simple. Any deep copy function only duplicates the containers of immutable objects. When you deepcopy a nested list, you are only duplicating the outer lists, not the mutable objects inside of the lists. You are only duplicating the containers. The same works for classes, too. When you deepcopy a class, you deepcopy all of its mutable attributes. So, how? How come you only have to copy the containers, like lists, dicts, tuples, iters, classes, and class instances?
It's simple. A mutable object can't really be duplicated. It can never be changed, so it is only a single value. That means you never have to duplicate strings, numbers, bools, or any of those. But how would you duplicate the containers? Simple. You make just initialize a new container with all of the values. Deepcopy relies on recursion. It duplicates all the containers, even ones with containers inside of them, until no containers are left. A container is an immutable object.
Once you know that, completely duplicating an object without any references is pretty easy. Here's a function for deepcopying basic data-types (wouldn't work for custom classes but you could always add that)
Python's own built-in deepcopy is based around that example. The only difference is it supports other types, and also supports user-classes by duplicating the attributes into a new duplicate class, and also blocks infinite-recursion with a reference to an object it's already seen using a memo list or dictionary. And that's really it for making deep copies. At its core, making a deep copy is just making shallow copies. I hope this answer adds something to the question.
EXAMPLES
Say you have this list:
[1, 2, 3]
. The immutable numbers cannot be duplicated, but the other layer can. You can duplicate it using a list comprehension:[x for x in [1, 2, 3]]
Now, imagine you have this list:
[[1, 2], [3, 4], [5, 6]]
. This time, you want to make a function, which uses recursion to deep copy all layers of the list. Instead of the previous list comprehension:It uses a new one for lists:
And deepcopy_list looks like this:
Then now you have a function which can deepcopy any list of strs, bools, floast, ints and even lists to infinitely many layers using recursion. And there you have it, deepcopying.
TLDR: Deepcopy uses recursion to duplicate objects, and merely returns the same immutable objects as before, as immutable objects cannot be duplicated. However, it deepcopies the most inner layers of mutable objects until it reaches the outermost mutable layer of an object.
请注意,在某些情况下,如果您已经定义了自己的自定义类并且要保留属性,则应使用
copy.copy()
或 copy.deepcopy()而不是替代方案,例如python 3:输出:
Note that there are some cases where if you have defined your own custom class and you want to keep the attributes then you should use
copy.copy()
orcopy.deepcopy()
rather than the alternatives, for example in Python 3:Outputs:
请记住,在Python中,当您使用时:
List2不是存储实际列表,而是对List1的引用。因此,当您对List1做任何事情时,List2也会更改。使用复制模块(不默认,在PIP上下载)来制作列表的原始副本(
copy.copy()
for简单列表,copy.deepcopy()
for嵌套)。这制作了一个不会随第一个列表而变化的副本。Remember that in Python when you do:
List2 isn't storing the actual list, but a reference to list1. So when you do anything to list1, list2 changes as well. use the copy module (not default, download on pip) to make an original copy of the list(
copy.copy()
for simple lists,copy.deepcopy()
for nested ones). This makes a copy that doesn't change with the first list.通过ID和GC查看内存的略有实际观点。
A slight practical perspective to look into memory through id and gc.
还有另一种复制列表到现在尚未列出的列表的方法:添加一个空列表:
l2 = l + []
。我用python 3.8进行了测试:
这不是最好的答案,但它起作用。
There is another way of copying a list that was not listed until now: adding an empty list:
l2 = l + []
.I tested it with Python 3.8:
It is not the best answer, but it works.
这是因为,行
new_list = my_list
为变量my_list
分配新的引用这类似于下面给出的
c
代码,您应该使用复制模块来创建一个新列表
This is because, the line
new_list = my_list
assigns a new reference to the variablemy_list
which isnew_list
This is similar to the
C
code given below,You should use the copy module to create a new list by
DeepCopy选项是对我有用的唯一方法:
导致输出的输出:
The deepcopy option is the only method that works for me:
leads to output of:
使用的方法取决于要复制列表的内容。如果该列表包含嵌套
dicts
而不是deepcopy是唯一有效的方法,否则答案中列出的大多数方法(slice,loop [for],复制,扩展,扩展,组合或解开)都可以使用并在类似的时间内执行(除了循环和deepcopy,这使最坏的情况更糟糕了)。脚本
结果
The method to use depends on the contents of the list being copied. If the list contains nested
dicts
than deepcopy is the only method that works, otherwise most of the methods listed in the answers (slice, loop [for], copy, extend, combine, or unpack) will work and execute in similar time (except for loop and deepcopy, which preformed the worst).Script
Results
要了解不同的python克隆/复制选项,请查看此代码,该代码“复制”了嵌套列表的三种不同的方式,并使用 memory_graph 要绘制结果:
全面披露:我是 memory_graph 。
To understand the different Python clone/copy options have a look at this code that "copies" a nested list three different ways and uses memory_graph to graph the result:
Full disclosure: I am the developer of memory_graph.
框架挑战:您是否需要复制应用程序?
我经常看到试图以某种迭代方式修改列表副本的代码。要构建一个微不足道的示例,假设我们有不工作(因为
x
不应修改)代码,例如:自然,人们会问如何制作
y
是<代码> x ,而不是同一列表的名称,因此循环的将做正确的事情。
但这是错误的方法。从功能上讲,我们真正想要做的是制作新列表,它是基于的原始> 。
我们不需要先制作副本就可以做到这一点,而且通常不应该这样做。
当我们需要将逻辑应用于每个元素时
,自然工具的自然工具就是列表的理解。这样,我们写下逻辑,告诉我们所需结果中的元素如何与原始元素相关。简单,优雅和富有表现力;而且,我们避免需要解决方法以修改
y
在 loop中复制复制(因为分配给迭代变量不会影响列表 - ,其原因是我们首先希望副本!)。在上面的示例中,它看起来像:
列表综合功能非常强大;我们还可以使用它们来通过规则过滤元素,并使用子句子句,并且我们可以为 and and
链条
(如果> renauses)(它的工作方式)相同的条款以相同的顺序 的相应代码;如果计划在修改副本“>避免问题)的情况下进行修改通过过滤列表的理解。当我们需要按位置拒绝或插入特定元素时,
假设我们有类似的东西,而
不是首先制作
y
首先删除我们不想要的零件,我们可以构建一个列表通过将我们 do 的零件放在一起。因此:通过切片处理插入,替换等。恰恰理解您希望结果包含哪些子序列。这样的一种特殊情况是进行反向副本 - 假设我们完全需要一个新列表(而不是仅仅是<倒向),我们可以直接通过切割而不是克隆,然后使用
reververs
来直接创建它。这些方法(例如列表理解)也具有将所需结果创建为表达式的优势,而不是通过程序将现有对象定为就地(和
Frame challenge: do you actually need to copy, for your application?
I often see code that tries to modify a copy of the list in some iterative fashion. To construct a trivial example, suppose we had non-working (because
x
should not be modified) code like:Naturally people will ask how to make
y
be a copy ofx
, rather than a name for the same list, so that thefor
loop will do the right thing.But this is the wrong approach. Functionally, what we really want to do is make a new list that is based on the original.
We don't need to make a copy first to do that, and we typically shouldn't.
When we need to apply logic to each element
The natural tool for this is a list comprehension. This way, we write the logic that tells us how the elements in the desired result, relate to the original elements. It's simple, elegant and expressive; and we avoid the need for workarounds to modify the
y
copy in afor
loop (since assigning to the iteration variable doesn't affect the list - for the same reason that we wanted the copy in the first place!).For the above example, it looks like:
List comprehensions are quite powerful; we can also use them to filter out elements by a rule with an
if
clause, and we can chainfor
andif
clauses (it works like the corresponding imperative code, with the same clauses in the same order; only the value that will ultimately end up in the result list, is moved to the front instead of being in the "innermost" part). If the plan was to iterate over the original while modifying the copy to avoid problems, there is generally a much more pleasant way to do that with a filtering list comprehension.When we need to reject or insert specific elements by position
Suppose instead that we had something like
Rather than making
y
a separate copy first in order to delete the part we don't want, we can build a list by putting together the parts that we do want. Thus:Handling insertion, replacement etc. by slicing is left as an exercise. Just reason out which subsequences you want the result to contain. A special case of this is making a reversed copy - assuming we need a new list at all (rather than just to iterate in reverse), we can directly create it by slicing, rather than cloning and then using
.reverse
.These approaches - like the list comprehension - also have the advantage that they create the desired result as an expression, rather than by procedurally modifying an existing object in-place (and returning
None
). This is more convenient for writing code in a "fluent" style.每个副本模式的简短说明:
a 浅副本构造一个新的复合对象,然后(在可能的程度上)将引用插入到原始中的对象中 - 创建浅副本
: 深层复制构建一个新的复合对象,然后递归地将副本插入原始的对象中 - 创建一个深拷贝:
list()
在深处工作正常简单列表的副本,例如:但是,对于
...
Short and simple explanations of each copy mode:
A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original - creating a shallow copy:
A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original - creating a deep copy:
list()
works fine for deep copy of simple lists, like:But, for complex lists like...
...use
deepcopy()
:因为: new_list 将仅是对 my_list 的参考,而在 new_list 中进行的更改也将在 my_list 反之亦然,
有两种复制列表
或
because: new_list will only be a reference to my_list, and changes made in new_list will automatically also be made in my_list and vice versa
There are two easy ways to copy a list
or