[英]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编写代码,除非你使用popitem
, move_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语言规范的官方部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.