繁体   English   中英

为什么python不包含有序的dict(默认情况下)?

[英]Why python does not include a ordered dict (by default)?

Python有一些很好的结构来建模数据。 这里有一些 :

              +-------------------+-----------------------------------+
              | indexed by int    | no-indexed by int                 |
+-------------+-------------------+-----------------------------------+
| no-indexed  | [1, 2, 3]         | {1, 2, 3}                         |
| by key      | or                | or                                |
|             | [x+1 in range(3)] | {x+1 in range(3)}                 |
+-------------+-------------------+-----------------------------------+
| indexed     |                   | {'a': 97, 'c': 99, 'b': 98}       |
| by key      |                   | or                                |
|             |                   | {chr(x):x for x in range(97,100)} |
+-------------+-------------------+-----------------------------------+

为什么python默认不包含由key + int索引的结构(如PHP数组)? 我知道有一个模拟这个对象的库( http://docs.python.org/3/library/collections.html#ordereddict-objects )。 但这里是从文档中获取的“orderedDict”的表示:

OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

拥有一个逻辑上应该写的本机类型不是更好吗:

['a': 97, 'b': 98, 'c': 99]

与orderedDict理解相同的逻辑:

[chr(x):x for x in range(97,100)]

在python设计中填充像这样的表格单元格是否有意义? 这有什么特别的原因尚未实施吗?

Python的字典被实现为哈希表。 这些本质上是无序的数据结构。 虽然可以添加额外的逻辑来跟踪顺序(如在Python 2.7和3.1+中的collections.OrderedDict中所做的那样),但是涉及到一个非平凡的开销。

例如, collections文档建议在Python 2.4-2.6中使用的配方需要两倍多的工作来完成许多基本字典操作(例如添加和删除值)。 这是因为它必须维护一个双向链表以用于有序迭代,并且它需要一个额外的字典来帮助维护列表。 虽然其操作仍为O(1),但常数项更大。

由于Python在任何地方使用dict实例(例如,对于所有变量查找),因此它们需要非常快或者每个程序的每个部分都会受到影响。 由于不经常需要有序迭代,因此在一般情况下避免它所需的开销是有意义的。 如果您需要有序字典,请使用标准库中的字典(或者它建议的配方,如果您使用的是早期版本的Python)。

您的问题似乎是“为什么Python没有带有序键的本机PHP样式数组?”

Python有三种核心非标量数据类型:list,dict和tuple。 Dicts和元组对于实现语言本身是绝对必要的:它们用于赋值,参数解包,属性查找等。虽然没有真正用于核心语言语义,但列表对于Python中的数据和程序非常重要。 这三个必须非常轻量级,具有非常好理解的语义,并且尽可能快。

PHP风格的数组都不是这些。 它们不是快速或轻量级的,运行时复杂性很差,并且它们混淆了语义,因为它们可以用于许多不同的东西 - 查看数组函数 它们实际上是几乎每个用例的可怕数据类型,除了它们被创建的非常窄的用例:表示x-www-form-encoded数据。 即使对于这个用例,失败的是早期的密钥会覆盖以后密钥的值:在PHP中?a=1&a=2导致array('a'=>2) (在Python中处理此问题的常见结构是MultiDict ,它具有有序键值,每个键可以有多个值。)

PHP有一种数据类型,几乎每个用例都必须使用它,而不适用于任何用例。 Python有许多不同的数据类型(一些核心,在外部库中更多),它们在更窄的用例中表现出色。

添加与更新信息的新的答案:以C Python3.6的, dicts维持秩序 虽然仍然无法索引。 很可能因为基于整数的项查找是不明确的,因为dict键可以是int。 (存在一些自定义用例。)

不幸的是, dict文档还没有更新以反映这个(还),并且仍然说“键和值以任意顺序迭代,这是非随机的” 具有讽刺意味的是, collections.OrderedDict文档提到了新的行为:

版本3.6中已更改 :接受PEP 468后 ,将保留传递给OrderedDict构造函数及其update()方法的关键字参数的顺序。

这里有一篇文章提到了一些有关它的更多细节

一个次要但有用的内部改进:Python 3.6保留了更多结构的元素顺序。 传递给函数的关键字参数,类中的属性定义和字典都保留了元素定义时的顺序。

因此,如果你只是为Py36编写代码,除非你使用popitemmove_to_end或基于顺序的相等,否则你不应该需要collections.OrderedDict

例如,在Python 2.7中:

>>> d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 0: None}
>>> d
{'a': 1, 0: None, 'c': 3, 'b': 2, 'd': 4}

在Python 3.6中:

>>> d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 0: None}
>>> d
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 0: None}
>>> d['new'] = 'really?'
>>> d[None]= None
>>> d
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 0: None, 'new': 'really?', None: None}
>>> d['a'] = 'aaa'
>>> d
{'a': 'aaa', 'b': 2, 'c': 3, 'd': 4, 0: None, 'new': 'really?', None: None}
>>> 
>>> # equality is not order-based
>>> d1 = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 0: None}
... d2 = {'b': 2, 'a': 1, 'd': 4, 'c': 3, 0: None}
>>> d2
{'b': 2, 'a': 1, 'd': 4, 'c': 3, 0: None}
>>> d1 == d2
True

从python 3.7开始,这现在是字典的默认行为,它是截至2018年6月采用的3.6中的实现细节:')

dict对象的插入顺序保存性质已被声明为Python语言规范的官方部分。

https://docs.python.org/3/whatsnew/3.7.html

暂无
暂无

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

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