词典的深度副本创建时理解不起作用

2024-04-19 06:10:10 发布

您现在位置:Python中文网/ 问答频道 /正文

你能帮助我理解为什么deepcopy不能适用于下面示例中字典中的所有元素吗

import copy
a = [{'id':1, 'list':[1,2,3], 'num':3}, {'id':2,' list':[4,5,6], 'num':65}]
b = {i['id']:copy.deepcopy(i) for i in a}

In [1]: print(id(a) == id(b))                                                                                                                      
Out[1]: False

In [2]: print(id(a[0]) == id(b[1]))                                                                                                                   
Out[2]: False

In [3]: print(id(a[0]['list']) == id(b[1]['list']))                                                                                                                   
Out[3]: False

In [4]: print(id(a[0]['num']) == id(b[1]['num']))                                                                                                        
Out[4]: True

特别是,与'num'键关联的值是相同的,而与'list'键关联的值似乎已通过deepcopy成功复制。我猜这与存储的值的数据类型有关,有人能给我指出正确的方向吗

谢谢


Tags: inimportidfalse元素示例for字典
2条回答

python中可变类型和不可变类型之间有很大的区别。 通常,Python中的变量类型包括列表、字典和集合。不可变类型包括字符串、int、float和元组。 重新分配不可变类型的变量实际上是重新创建不可变类型的对象,并将原始变量重新指向新创建的对象(打开新的内存地址),如果没有其他变量引用原始对象(即引用计数为0),则原始对象将被回收

这与听写理解无关,但正如您所建议的,与数据类型有关:

>>> import copy
>>> x = 1
>>> copy.deepcopy(x) is x
True
>>> x = [1]
>>> copy.deepcopy(x) is x
False

@mengban的区别是正确的:您有可变和不可变的对象(这取决于对象的类型)。不可变对象的典型示例有:整数(012……、浮点数(3.14159),还有字符串("foo")和元组((1, 3))。可变对象的典型示例有:列表([1, 2, 3])或字典({'a': 1, 'b': 2}

基本上,不可变对象的deepcopy返回对象本身:不执行实际的复制(元组有一个小技巧:我稍后会解释):

>>> x = "foo"
>>> copy.deepcopy(x) is x
True
>>> x = (1, 2)
>>> copy.deepcopy(x) is x
True

可变对象的deepcopy创建具有相同元素的对象的新实例

这是正确的行为,因为当您获得对象o的深度副本o2时,契约是这是您的副本。对o执行的任何操作都不能修改o2。如果o是不可变的,这是免费保证的。但是如果o是可变的,那么您需要创建一个具有相同内容的新实例(这意味着一个递归深度副本)

现在元组怎么了

>>> o = ([1], [2])
>>> copy.deepcopy(o) is o
False

即使元组本身是不可变的,它的一个元素也可能是可变的。如果我给你一个o2o(即o2 = o)值的引用,你可以写o2[0].append(10),我的对象o被修改。因此deepcopy函数在元组中查找可变对象,并决定是否需要实际副本


奖励:看一下^{} implementation_deepcopy_dispatch将类型映射到实际的复印机:

_deepcopy_dispatch = d = {}

...
d[int] = _deepcopy_atomic
d[float] = _deepcopy_atomic
d[bool] = _deepcopy_atomic
...
d[str] = _deepcopy_atomic
...
d[list] = _deepcopy_list
...
d[tuple] = _deepcopy_tuple
...
d[dict] = _deepcopy_dict
...

_deepcopy_atomic只是返回值,_deepcopy_list_deepcopy_tuple_deepcopy_dict。。。通常进行深入复制

您可以检查^{} function以了解该过程。基本上,深度复制每个元素,直到实际复制完成。如果创建了副本,则创建一个新的深度副本元组。否则返回初始元组

相关问题 更多 >