drs*_*lck 16 python dictionary ipython python-3.x python-3.6
我正在玩OrderedDictPython 3.6中的类型,并且对它的行为感到惊讶.当我dict在IPython中创建这样的简单时:
d = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
Run Code Online (Sandbox Code Playgroud)
我明白了:
{'guido': 4127, 'jack': 4098, 'sape': 4139}
Run Code Online (Sandbox Code Playgroud)
作为输出,由于某种原因,它不会在实例化时保留元素的顺序.现在,当我创建一个OrderedDict从d这样的:
od = OrderedDict(d)
Run Code Online (Sandbox Code Playgroud)
输出是:
OrderedDict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
Run Code Online (Sandbox Code Playgroud)
现在我问自己,OrderedDict-constructor 如何知道实例化时元素的顺序d?并且它总是表现相同,这样我可以依赖于元素的顺序OrderedDict吗?
我已经阅读了关于字典和OrderedDicts 的Python文档,但我没有找到我的问题的答案.
来自(sys.version)的输出:
In[22]: sys.version
Out[22]: '3.6.1 (default, Apr 4 2017, 09:40:21) \n[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)]'
Run Code Online (Sandbox Code Playgroud)
Jim*_*ard 12
现在很明显,sys.displayhookIPython用于显示输出的自定义hook()非常适合打印(使用它自己漂亮的打印机).
通过直接调用,displayhook您可以看到它如何破坏插入顺序:
In [1]: from sys import displayhook
...: displayhook({'1': 0, '0': 1})
Out[1]: {'0': 1, '1': 0}
Run Code Online (Sandbox Code Playgroud)
此外,如果您str改为抓取字典(发送要显示的字符串而不是dict对象),您将获得正确和预期的顺序:
In [2]: d = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
...: d
Out[2]: {'guido': 4127, 'jack': 4098, 'sape': 4139}
In [3]: str(dict(t))
Out[3]: "{'sape': 4139, 'guido': 4127, 'jack': 4098}"
Run Code Online (Sandbox Code Playgroud)
同样通过print它.
我不确定为什么IPython会这样做3.6,这很混乱(编辑:请参阅GitHub上的相关问题).在您的标准Python REPL中,此行为将不会显示,因为sys.displayhook没有实现任何漂亮的打印.
d您创建的字典确实维护了插入顺序,这OrderedDict就是维持相同顺序的原因.
当然,它确实是一个实现细节.在改变之前(并且确实会出现这种情况),您应该坚持使用OrderedDict可靠地维护跨实现的顺序.
顺便说一句,如果你想要禁用它,你可以使用--no-pprint禁用其漂亮的打印机的选项启动IPython :
? ipython --no-banner --no-pprint
In [1]: dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
Out[1]: {'sape': 4139, 'guido': 4127, 'jack': 4098}
Run Code Online (Sandbox Code Playgroud)
在3.6中,作为实现细节,所有dicts都是有序的.你被IPython愚弄了:在3.6之前,键的顺序是任意的,所以为了用户友好性,IPython的交互式输出dict和set(普通的Python只会打印repr)对键进行排序.这就是为什么你dict看起来按字母顺序排列的原因.在3.6+上运行时,IPython最终可能会放弃这种行为,因为正如你所注意到的那样,它非常令人困惑.
如果你明确地print,而不是依赖于ipython为你输出前一个表达式的结果,你将绕过ipython'REPL魔术并看到"自然"顺序.对于任何其他与之交互的方式也是如此dict,因为迭代将以预期的顺序进行.