繁体   English   中英

有序字典的深层副本是否有望保留其顺序?

[英]Is deepcopy of an ordered dictionary expected to preserve its order?

我做了一个小程序并测试它确实保持顺序。 但是,我仍然想确保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正确实现复制应产生一个与原始对象相同的对象(假设完全定义了相等性)。 虽然没有,但是没有关于OrderedDictcopy.deepcopy明确记录保证,如果副本中OrderedDict的顺序发生变化,它将不等于原始的OrderedDict ,这将大大违反复制相等的期望。 。

没有确切的保证,因为密钥或值的__deepcopy__方法可以做一些非常糟糕的事情(例如修改源OrderedDict ),但除了病态情况之外,你可以依靠copy.deepcopy来保持排序。

在CPython中,似乎保留了订单。 我从检查deepcopy的实现中得出了这个结论。 在这种情况下,它会在OrderedDict对象上找到__reduce_ex____reduce__方法用于酸洗:

https://github.com/python/cpython/blob/master/Lib/copy.py#L159-L161

def deepcopy(x, memo=None, _nil=[]):
...
                    reductor = getattr(x, "__reduce_ex__", None)
                    if reductor is not None:
                        rv = reductor(4)
                    else:
                        reductor = getattr(x, "__reduce__", None)
                        if reductor:
                            rv = reductor()

那些返回用于构造的odict_iterator对象,因此将保留顺序:

>>> 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>)
>>> 

对象的深度复制应该返回相同类型的对象。 所以,作为副本返回的有序指令应该仍然有序?

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

由于有些人可能会来这里寻找与 dict(标准 dict,而不是 OrderedDict)相关的答案,我认为这会很有用:在 Python 3.6 或更高版本中,为 dict 保留了顺序,因此 dict 的 deepcopy 将得到排序免费。 (如果您担心实现与规范,那么请使用 python 3.7,因为它现在是 3.7 语言规范)

请参阅相关问题: Can I get JSON to load into an OrderedDict? 另请参阅有关使用 OrderedDict 保留 oder 的评论: https : //gandenberger.org/2018/03/10/ordered-dicts-vs-ordereddict/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM