为什么** kwargs映射与不同排序的OrderedDict相等?

时间:2018-03-07 18:50:04

标签: python function python-3.6 ordereddictionary kwargs

根据PEP 468

  

从版本3.6开始,Python将保留传递给函数的关键字参数的顺序。为实现此目的,收集的 kwargs现在将成为有序映射。请注意,这并不一定意味着OrderedDict

在这种情况下,为什么这个有序映射无法遵守与Python的规范有序映射类型collections.OrderedDict

的等式比较
>>> from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return kwargs == data
... 
>>> foo(x='x', y='y')  # expected result: True
True
>>> foo(y='y', x='x')  # expected result: False
True

虽然现在保留了迭代顺序,但kwargs似乎表现得像比较的普通字典。 Python有一个C实现的有序字典since 3.5,所以它可以直接使用(或者,如果性能仍然是一个问题,使用3.6紧凑字典的瘦子类更快的实现)。

为什么函数收到的有序映射不会在相等比较中遵循排序?

4 个答案:

答案 0 :(得分:14)

无论“有序映射”的含义如何,只要它不一定是OrderedDictOrderedDict的{​​{1}}就不会考虑其顺序。 Docs:

  

==个对象之间的平等测试是对订单敏感的,并且实现为OrderedDict list(od1.items())==list(od2.items())对象与其他OrderedDict对象之间的等同性测试对常规字典顺序不敏感。这允许在使用常规字典的任何地方替换Mapping个对象。

答案 1 :(得分:9)

"有序映射"仅表示映射必须保留顺序。它并不意味着订单必须是映射的==关系的一部分。

PEP 468的目的只是为了保存订购信息。将命令作为==的一部分将产生向后不兼容性,而不会对促使PEP 468的任何用例产生任何实际好处。使用OrderedDict也会更加昂贵(因为OrderedDict仍然保持其拥有单独的链接列表来跟踪订单,它不会放弃该链接列表而不会牺牲popitemmove_to_end中的大O效率。

答案 2 :(得分:6)

第一个“为什么”的答案是因为此功能是通过在CPython中使用普通d3.json("canada.json", function(data) { var projection = fitProjection(d3.geo.mercator(), data, [[0, 0], [width, height]], true) var path = d3.geo.path().projection(projection); d3.select("#statesvg svg").remove(); var svg = d3.select("#statesvg").append("svg") .attr("width", width+"px") .attr("height", height+"px"); svg.selectAll("path") .data(data.features) .enter() .append("path") .attr("d", path) .style("stroke", "#fff") .style("stroke-width", "1") .style("fill", function(d) { return "rgb(213,222,217)"; }); }); 来实现的。正如@ Ryan的答案指出的那样,这意味着比较不会对订单敏感。

第二个'为什么'这就是为什么这不使用dict

使用OrderedDict是PEP 486的first draft中所述的初始计划。如in this reply所述,该想法是收集一些性能数据以显示堵塞的效果OrderedDict中的OrderedDict,因为这是一个争论点,当时这个想法浮出水面。 PEP的作者甚至提到保留dict的命令是该线程final reply中的另一个选项。

之后,关于该主题的对话似乎已经消失,直到Python 3.6出现。当新的词典出现时,它具有开箱即用的PEP 486的良好副作用(如this Python-dev thread states)。该线程中的特定消息还说明了作者如何将术语OrderedDict更改为有序映射。 (这也是在new commit on PEP 468之后,在最初的一个之后)

据我所知,这个重写是为了让其他实现能够提供他们认为合适的功能。 CPython和PyPy已经有了一个可以轻松实现PEP 468的字典,其他实现可能会选择OrderedDict,其他实现可以选择其他形式的有序映射。

但是,这确实为问题打开了大门。理论上,它确实意味着在Python 3.6的实现中使用OrderedDict作为实现此功能的结构,比较将是顺序敏感的,而在其他(CPython)它不会。 (在Python 3.7中,所有dict都需要按顺序排序,所以这一点可能没有实际意义,因为所有实现都会将它用于**kwargs

虽然看起来确实是一个问题,但事实并非如此。正如@ user2357112指出的那样,==无法保证。 PEP 468 保证订单。据我所知,==基本上是实现定义的。

简而言之,它比较了CPython 中的,因为CPython中的kwargsdict而且它是dict,因为3.6之后整个事情刚刚奏效。

答案 3 :(得分:1)

只是要添加,如果你确实想要进行这项检查(不依赖于实现细节(即便如此,它不会在python 3.7中),只需要做

from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
...     return OrderedDict(kwargs) == data

因为这保证是真的。