Python 有序词典的deepcopy是否需要保持其顺序?

Python 有序词典的deepcopy是否需要保持其顺序?,python,deep-copy,ordereddictionary,Python,Deep Copy,Ordereddictionary,我制作了一个小程序,并测试了它是否保持了顺序。但是,我仍然希望确保deepcopy能够做到这一点 import copy import collections a_dict = collections.OrderedDict() a_dict['m'] = 10 a_dict['u'] = 15 a_dict['c'] = 5 a_dict['h'] = 25 a_dict['a'] = 55 a_dict['s'] = 30 print(a_dict) other_dict = copy

我制作了一个小程序,并测试了它是否保持了顺序。但是,我仍然希望确保
deepcopy
能够做到这一点

import copy
import collections

a_dict = collections.OrderedDict()
a_dict['m'] = 10
a_dict['u'] = 15
a_dict['c'] = 5
a_dict['h'] = 25
a_dict['a'] = 55
a_dict['s'] = 30

print(a_dict)

other_dict = copy.deepcopy(a_dict)

other_dict['g'] = 75
other_dict['r'] = 35

print(other_dict)
这个程序的输出是

OrderedDict([('m', 10), ('u', 15), ('c', 5), ('h', 25), ('a', 55), ('s', 30)])
OrderedDict([('m', 10), ('u', 15), ('c', 5), ('h', 25), ('a', 55), ('s', 30), ('g', 75), ('r', 35)])

通过
copy正确执行复制。deepcopy
应生成与原始对象相等的对象(假设定义了相等)。虽然没有,但没有关于
OrderedDict
copy.deepcopy
的明确书面保证。具体而言,如果
OrderedDict
的顺序在副本中发生变化,它将不等于原始的
OrderedDict
,这将在很大程度上违反复制平等的预期


由于键或值的
\uuuu deepcopy\uuuuu
方法可能会做一些真正可怕的事情(例如修改源
OrderedDict
),因此无法真正给出可靠的保证,但除了病理情况,您可以依靠
copy.deepcopy
来保持顺序。

对象的deepcopy应返回相同类型的对象。那么作为副本返回的OrderedICT应该保持订购状态


编辑-这不是完全正确的答案。请看下面格雷格的评论。

在CPython中,似乎保留了订单。我通过检查
deepcopy
的实施情况得出了这一结论。在这种情况下,它将在
OrderedDict
对象上找到用于酸洗的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

()

这些函数返回用于构造的
odict\u迭代器
对象,因此将保留顺序:

>>> a = {}
>>> b = collections.OrderedDict()
>>> a['a'] = 1
>>> b['a'] = 1
>>> a.__reduce_ex__(4)
(<function __newobj__ at 0x10471a158>, (<class 'dict'>,), None, None, <dict_itemiterator object at 0x104b5d958>)
>>> a.__reduce__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copyreg.py", line 65, in _reduce_ex
    raise TypeError("can't pickle %s objects" % base.__name__)
TypeError: can't pickle dict objects
>>> b.__reduce_ex__(4)
(<class 'collections.OrderedDict'>, (), None, None, <odict_iterator object at 0x104c02d58>)
>>> b.__reduce__()
(<class 'collections.OrderedDict'>, (), None, None, <odict_iterator object at 0x104c5c780>)
>>> 
>a={}
>>>b=集合。OrderedDict()的
>>>a['a']=1
>>>b['a']=1
>>>a.。uuu减少_uu前(4)
(,(,),无,无,)
>>>a.减少
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copyreg.py”,第65行,在
raise TypeError(“无法pickle%s对象”%base.\u name\u)
TypeError:无法pickle dict对象
>>>b.(4)减少(4)
(,(),无,无)
>>>b.减少
(,(),无,无)
>>> 

您必须查看c代码,看看deepcopy是否能够复制定义ordereddicts订单的链表。我猜这是可行的。在
复制
模块中,似乎没有为
OrderedDict
设置特殊的大小写,这意味着它最终会进行酸洗和取消酸洗以执行深度复制;返回
迭代器作为其返回的
元组的第五项
,根据
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
文档,这是迭代器,因此实现有意保留顺序。我不敢相信你会将答案中最酷的部分放在注释中:)@GregSchmit:这是Python,所以实现细节不是官方的;规范是文档,而不是CPython参考解释器;实施细节可能因版本和口译员而异。没有什么特别要求选择特定的实现(尽管这是一个简单的实现);理论上,其他一些Python解释器可能会选择不同的解释器。我不认为OP怀疑他们会得到另一个
OrderedDict
,他们只是担心新版本可能有不同的顺序。好的。如果返回的对象是OrderedDict,是否应该对其进行排序?如果返回的对象是OrderedDict而不是ordered,那么它违反了数据结构的定义。这正是我想表达的观点。@mod0,那么我认为你不理解OrderedDicts的工作原理。它们保持添加对象的顺序,因此如果两个对象的顺序不同,则不一定知道哪一个是“正确的”。问题是是否保留了相同的顺序,这并不像您所暗示的那样是给定的,因为在复制过程中,口译员可能会以不同的顺序复制,因此会返回不同的顺序数据。@GregSchmit您是对的。很抱歉,我假设钥匙已分类。我将编辑我的答案以反映这一点。@mod0它发生了;别担心!
>>> a = {}
>>> b = collections.OrderedDict()
>>> a['a'] = 1
>>> b['a'] = 1
>>> a.__reduce_ex__(4)
(<function __newobj__ at 0x10471a158>, (<class 'dict'>,), None, None, <dict_itemiterator object at 0x104b5d958>)
>>> a.__reduce__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/copyreg.py", line 65, in _reduce_ex
    raise TypeError("can't pickle %s objects" % base.__name__)
TypeError: can't pickle dict objects
>>> b.__reduce_ex__(4)
(<class 'collections.OrderedDict'>, (), None, None, <odict_iterator object at 0x104c02d58>)
>>> b.__reduce__()
(<class 'collections.OrderedDict'>, (), None, None, <odict_iterator object at 0x104c5c780>)
>>>