如何在 Python 中创建对象的副本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4794244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I create a copy of an object in Python?
提问by Roman
I would like to create a copy of an object. I want the new object to possess all properties of the old object (values of the fields). But I want to have independent objects. So, if I change values of the fields of the new object, the old object should not be affected by that.
我想创建一个对象的副本。我希望新对象拥有旧对象的所有属性(字段的值)。但我想拥有独立的对象。因此,如果我更改新对象的字段值,旧对象不应受到影响。
采纳答案by Sven Marnach
To get a fully independent copy of an object you can use the copy.deepcopy()function.
要获得对象的完全独立副本,您可以使用该copy.deepcopy()函数。
For more details about shallow and deep copying please refer to the other answers to this question and the nice explanation in this answer to a related question.
有关浅复制和深复制的更多详细信息,请参阅此问题的其他答案以及此相关问题的答案中的精彩解释。
回答by Aaron Hall
How can I create a copy of an object in Python?
So, if I change values of the fields of the new object, the old object should not be affected by that.
如何在 Python 中创建对象的副本?
因此,如果我更改新对象的字段值,旧对象不应受到影响。
You mean a mutable object then.
那么你的意思是一个可变对象。
In Python 3, lists get a copymethod (in 2, you'd use a slice to make a copy):
在 Python 3 中,列表获得一个copy方法(在 2 中,您将使用切片来制作副本):
>>> a_list = list('abc')
>>> a_copy_of_a_list = a_list.copy()
>>> a_copy_of_a_list is a_list
False
>>> a_copy_of_a_list == a_list
True
Shallow Copies
浅拷贝
Shallow copies are just copies of the outermost container.
浅拷贝只是最外层容器的拷贝。
list.copyis a shallow copy:
list.copy是浅拷贝:
>>> list_of_dict_of_set = [{'foo': set('abc')}]
>>> lodos_copy = list_of_dict_of_set.copy()
>>> lodos_copy[0]['foo'].pop()
'c'
>>> lodos_copy
[{'foo': {'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
You don't get a copy of the interior objects. They're the same object - so when they're mutated, the change shows up in both containers.
您不会获得内部对象的副本。它们是同一个对象——所以当它们发生变异时,变化会出现在两个容器中。
Deep copies
深拷贝
Deep copies are recursive copies of each interior object.
深拷贝是每个内部对象的递归拷贝。
>>> lodos_deep_copy = copy.deepcopy(list_of_dict_of_set)
>>> lodos_deep_copy[0]['foo'].add('c')
>>> lodos_deep_copy
[{'foo': {'c', 'b', 'a'}}]
>>> list_of_dict_of_set
[{'foo': {'b', 'a'}}]
Changes are not reflected in the original, only in the copy.
更改不会反映在原件中,只会反映在副本中。
Immutable objects
不可变对象
Immutable objects do not usually need to be copied. In fact, if you try to, Python will just give you the original object:
不可变对象通常不需要复制。实际上,如果您尝试这样做,Python 只会给您原始对象:
>>> a_tuple = tuple('abc')
>>> tuple_copy_attempt = a_tuple.copy()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'copy'
Tuples don't even have a copy method, so let's try it with a slice:
元组甚至没有复制方法,所以让我们用切片试试:
>>> tuple_copy_attempt = a_tuple[:]
But we see it's the same object:
但我们看到它是同一个对象:
>>> tuple_copy_attempt is a_tuple
True
Similarly for strings:
同样对于字符串:
>>> s = 'abc'
>>> s0 = s[:]
>>> s == s0
True
>>> s is s0
True
and for frozensets, even though they have a copymethod:
而对于frozensets,即使他们有一个copy方法:
>>> a_frozenset = frozenset('abc')
>>> frozenset_copy_attempt = a_frozenset.copy()
>>> frozenset_copy_attempt is a_frozenset
True
When to copy immutable objects
何时复制不可变对象
Immutable objects shouldbe copied if you need a mutable interior object copied.
如果您需要复制可变内部对象,则应复制不可变对象。
>>> tuple_of_list = [],
>>> copy_of_tuple_of_list = tuple_of_list[:]
>>> copy_of_tuple_of_list[0].append('a')
>>> copy_of_tuple_of_list
(['a'],)
>>> tuple_of_list
(['a'],)
>>> deepcopy_of_tuple_of_list = copy.deepcopy(tuple_of_list)
>>> deepcopy_of_tuple_of_list[0].append('b')
>>> deepcopy_of_tuple_of_list
(['a', 'b'],)
>>> tuple_of_list
(['a'],)
As we can see, when the interior object of the copy is mutated, the original does notchange.
我们可以看到,当副本的内部对象发生变异时,原始对象并没有改变。
Custom Objects
自定义对象
Custom objects usually store data in a __dict__attribute or in __slots__(a tuple-like memory structure.)
自定义对象通常将数据存储在__dict__属性或__slots__(类似元组的内存结构)中。
To make a copyable object, define __copy__(for shallow copies) and/or __deepcopy__(for deep copies).
要制作可复制的对象,请定义__copy__(对于浅拷贝)和/或__deepcopy__(对于深拷贝)。
from copy import copy, deepcopy
class Copyable:
__slots__ = 'a', '__dict__'
def __init__(self, a, b):
self.a, self.b = a, b
def __copy__(self):
return type(self)(self.a, self.b)
def __deepcopy__(self, memo): # memo is a dict of id's to copies
id_self = id(self) # memoization avoids unnecesary recursion
_copy = memo.get(id_self)
if _copy is None:
_copy = type(self)(
deepcopy(self.a, memo),
deepcopy(self.b, memo))
memo[id_self] = _copy
return _copy
Note that deepcopykeeps a memoization dictionary of id(original)(or identity numbers) to copies. To enjoy good behavior with recursive data structures, make sure you haven't already made a copy, and if you have, return that.
请注意,deepcopy将id(original)(或身份号码)的记忆字典保存到副本中。要享受递归数据结构的良好行为,请确保您尚未复制,如果有,请将其返回。
So let's make an object:
所以让我们创建一个对象:
>>> c1 = Copyable(1, [2])
And copymakes a shallow copy:
并copy制作一个浅拷贝:
>>> c2 = copy(c1)
>>> c1 is c2
False
>>> c2.b.append(3)
>>> c1.b
[2, 3]
And deepcopynow makes a deep copy:
而deepcopy现在做了深刻的副本:
>>> c3 = deepcopy(c1)
>>> c3.b.append(4)
>>> c1.b
[2, 3]
回答by Alexey
I believe the following should work with many well-behaved classed in Python:
我相信以下内容应该适用于 Python 中的许多表现良好的分类:
def copy(obj):
return type(obj)(obj)
(Of course, I am not talking here about "deep copies," which is a different story, and which may be not a very clear concept -- how deep is deep enough?)
(当然,我在这里说的不是“深拷贝”,这是另一回事,可能不是一个很清晰的概念——多深才够深?)
According to my tests with Python 3, for immutable objects, like tuples or strings, it returns the same object (because there is no need to make a shallow copy of an immutable object), but for lists or dictionaries it creates an independent shallow copy.
根据我对 Python 3 的测试,对于不可变对象,如元组或字符串,它返回相同的对象(因为不需要制作不可变对象的浅拷贝),但对于列表或字典,它会创建一个独立的浅拷贝.
Of course this method only works for classes whose constructors behave accordingly. Possible use cases: making a shallow copy of a standard Python container class.
当然,此方法仅适用于其构造函数行为相应的类。可能的用例:制作标准 Python 容器类的浅拷贝。

