在python中的字典的深拷贝

Oli*_*ire 290 python python-3.x

我想dict在python中制作一个深层副本.不幸的是,该.deepcopy()方法不存在dict.我怎么做?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7
Run Code Online (Sandbox Code Playgroud)

最后一行应该是3.

我希望这些修改my_dict不会影响快照my_copy.

我怎么做?该解决方案应与Python 3.x兼容.

ang*_*son 415

怎么样:

import copy
d = { ... }
d2 = copy.deepcopy(d)
Run Code Online (Sandbox Code Playgroud)

Python 2或3:

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是`copy.deepcopy`不是线程安全的.很难理解这一点.另一方面,根据你的用例,`json.loads(json.dumps(d))`_is_线程安全,并且运行良好. (25认同)
  • 事实上,这适用于我给出的过于简单的例子.我的钥匙不是数字而是物体.如果我阅读了复制模块文档,我必须为密钥声明__copy __()/ __ deepcopy __()方法.非常感谢你带领我到那里! (15认同)
  • @rob 您应该将该评论作为答案发布。这是一个可行的替代方案。线程安全的细微差别是一个重要的区别。 (6认同)
  • Python 3.2和2.7代码有什么区别吗?他们看起来和我一模一样.如果是这样,那么单个代码块和声明"适用于Python 3和2"会更好 (3认同)
  • @BuvinJ问题是`json.loads`并没有解决python`dict`属性不是JSON可序列化的所有用例的问题.它可以帮助那些只处理简单数据结构的人,例如API,但我认为这不足以完全回答OP的问题. (2认同)
  • 另一个有趣的事实: dict 的 deepcopy 并不总是保留元素的顺序: `d = dict() ; 对于范围 (8) 中的 n: d[(n,n+1)] = n ;断言 d.keys() == copy.deepcopy(d).keys() ` (2认同)
  • “线程安全”是一个毫无意义的术语,除非您使用它的反义词“非线程安全”。线程安全意味着对行为的期望,但它没有详细说明*哪个*行为。库作者所考虑的线程安全可能与库用户所考虑的不同。例如,如果在多个线程上使用集合,那么它不会破坏自身就足够了吗?您是否需要检查“count &gt; 0”,然后隐式读取第一项以保持一致?一般来说,只要读取内容没有副作用,*读取*就是线程安全的。 (2认同)

the*_*der 30

dict.copy()是一个浅复制函数,用于字典
id是内置函数,它为您提供变量的地址

首先,您需要了解"为什么会出现这个特殊问题?"

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104
Run Code Online (Sandbox Code Playgroud)

键'a'的两个词组中出现的列表的地址指向相同的位置.
因此,当您更改my_dict中列表的值时,my_copy中的列表也会更改.


解:

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176
Run Code Online (Sandbox Code Playgroud)

或者您可以使用上面提到的深度复制.

  • 您的解决方案不适用于嵌套词典。因此,最好使用deepcopy。 (3认同)
  • @CharlesPlager同意!但您还应该注意,列表切片对dict`value [:]`不起作用。解决方案是针对问题中提到的特定数据结构,而不是通用解决方案。 (2认同)

xpr*_*ros 14

Python 3.x

从复制导入deepcopy

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)
Run Code Online (Sandbox Code Playgroud)

没有深度复制,我无法从我的域字典中删除主机名字典.

没有深度复制我收到以下错误:

"RuntimeError: dictionary changed size during iteration"
Run Code Online (Sandbox Code Playgroud)

...当我尝试从另一个字典里面的字典中删除所需的元素时.

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy
Run Code Online (Sandbox Code Playgroud)

domain是一个字典对象

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain
Run Code Online (Sandbox Code Playgroud)

示例输出:[ orginal ] domains = {'localdomain':{'localhost':{'all':'4000'}}}

[new] domains = {'localdomain':{}}}

所以这里发生的事情是我正在迭代字典的副本而不是遍历字典本身.使用此方法,您可以根据需要删除元素.