根据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紧凑字典的瘦子类更快的实现)。
为什么函数收到的有序映射不会在相等比较中遵循排序?
答案 0 :(得分:14)
无论“有序映射”的含义如何,只要它不一定是OrderedDict
,OrderedDict
的{{1}}就不会考虑其顺序。 Docs:
==
个对象之间的平等测试是对订单敏感的,并且实现为OrderedDict
。list(od1.items())==list(od2.items())
对象与其他OrderedDict
对象之间的等同性测试对常规字典顺序不敏感。这允许在使用常规字典的任何地方替换Mapping
个对象。
答案 1 :(得分:9)
"有序映射"仅表示映射必须保留顺序。它并不意味着订单必须是映射的==
关系的一部分。
PEP 468的目的只是为了保存订购信息。将命令作为==
的一部分将产生向后不兼容性,而不会对促使PEP 468的任何用例产生任何实际好处。使用OrderedDict
也会更加昂贵(因为OrderedDict
仍然保持其拥有单独的链接列表来跟踪订单,它不会放弃该链接列表而不会牺牲popitem
和move_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
,其他实现可以选择其他形式的有序映射。
OrderedDict
作为实现此功能的结构,比较将是顺序敏感的,而在其他(CPython)它不会。 (在Python 3.7中,所有dict
都需要按顺序排序,所以这一点可能没有实际意义,因为所有实现都会将它用于**kwargs
)
虽然看起来确实是一个问题,但事实并非如此。正如@ user2357112指出的那样,==
无法保证。 PEP 468 仅保证订单。据我所知,==
基本上是实现定义的。
简而言之,它比较了CPython 中的,因为CPython中的kwargs
是dict
而且它是dict
,因为3.6
之后整个事情刚刚奏效。
答案 3 :(得分:1)
只是要添加,如果你确实想要进行这项检查(不依赖于实现细节(即便如此,它不会在python 3.7中),只需要做
from collections import OrderedDict
>>> data = OrderedDict(zip('xy', 'xy'))
>>> def foo(**kwargs):
... return OrderedDict(kwargs) == data
因为这保证是真的。