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

Python 词典的深度副本创建时理解不起作用,python,deep-copy,dictionary-comprehension,Python,Deep Copy,Dictionary Comprehension,您能帮助我理解为什么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))

您能帮助我理解为什么
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'
键的值似乎已通过
深度复制成功复制。我猜这与存储的值的数据类型有关,有人能给我指出正确的方向吗


谢谢

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

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

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

>>> import copy
>>> x = 1
>>> copy.deepcopy(x) is x
True
>>> x = [1]
>>> copy.deepcopy(x) is x
False
@mengban的区别是正确的:您有可变和不可变的对象(这取决于对象的类型)。不可变对象的典型示例有:整数(
0
1
2
)、浮点数(
3.14159
),还有字符串(
“foo”
)和元组(
(1,3)
)。可变对象的典型示例有:列表(
[1,2,3]
)或字典(
{'a':1,'b':2}

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

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

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

现在元组怎么了

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


奖励:看一看。
\u deepcopy\u 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
...
虽然
\u deepcopy\u atomic
只返回值,
\u deepcopy\u list
\u deepcopy\u tuple
\u deepcopy\u dict
。。。通常进行深入复制


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

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

>>> import copy
>>> x = 1
>>> copy.deepcopy(x) is x
True
>>> x = [1]
>>> copy.deepcopy(x) is x
False
@mengban的区别是正确的:您有可变和不可变的对象(这取决于对象的类型)。不可变对象的典型示例有:整数(
0
1
2
)、浮点数(
3.14159
),还有字符串(
“foo”
)和元组(
(1,3)
)。可变对象的典型示例有:列表(
[1,2,3]
)或字典(
{'a':1,'b':2}

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

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

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

现在元组怎么了

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


奖励:看一看。
\u deepcopy\u 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
...
虽然
\u deepcopy\u atomic
只返回值,
\u deepcopy\u list
\u deepcopy\u tuple
\u deepcopy\u dict
。。。通常进行深入复制

您可以查看以了解