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设计中填充像这样的表格单元格是否有意义? 这有什么特别的原因尚未实施吗?
答案 0 :(得分:17)
Python的字典作为哈希表实现。这些本质上是无序的数据结构。虽然可以添加额外的逻辑来跟踪顺序(如在Python 2.7和3.1+中的collections.OrderedDict
中所做的那样),但是涉及到一个非平凡的开销。
例如,the recipe that the collections
documentation suggest for use in Python 2.4-2.6需要的工作量是完成许多基本字典操作(例如添加和删除值)的两倍多。这是因为它必须维护一个双向链表以用于有序迭代,并且它需要一个额外的字典来帮助维护列表。虽然它的操作仍然是O(1),但常数项更大。
由于Python在任何地方使用dict
实例(例如,对于所有变量查找),因此它们需要非常快或每个程序的每个部分都会受到影响。由于不经常需要有序迭代,因此在一般情况下避免它所需的开销是有意义的。如果您需要有序字典,请使用标准库中的字典(或者它建议的配方,如果您使用的是早期版本的Python)。
答案 1 :(得分:4)
您的问题似乎是“为什么Python没有带有序键的本机PHP样式数组?”
Python有三种核心非标量数据类型:list,dict和tuple。 Dicts和元组对于实现语言本身是绝对必要的:它们用于赋值,参数解包,属性查找等。虽然没有真正用于核心语言语义,但列表对于Python中的数据和程序非常重要。这三个必须非常轻量级,具有非常好理解的语义,并且尽可能快。
PHP风格的数组都不是这些。它们不是快速或轻量级的,运行时复杂性很差,而且它们混淆了语义,因为它们可以用于许多不同的事情 - 请看array functions。对于几乎所有用例,它们实际上都是可怕的数据类型,除了创建它们的非常窄的用例:表示x-www-form-encoded
数据。即使对于这个用例,失败的是早期的密钥会覆盖以后密钥的值:在PHP ?a=1&a=2
中会导致array('a'=>2)
。 (在Python中处理此问题的一个常见结构是MultiDict,它已经订购了键和值,并且每个键都可以有多个值。)
PHP有一种数据类型,几乎每个用例都必须使用它,而不是对任何用例都很好。 Python有许多不同的数据类型(一些核心,在外部库中更多),它们在更窄的用例中表现出色。
答案 2 :(得分:1)
添加包含更新信息的新答案:从 C Python3.6开始, dicts
保留订单。虽然仍然无法索引。很可能因为基于整数的项查找是不明确的,因为dict键可以是int。 (存在一些自定义用例。)
不幸的是,documentation for dict
尚未更新以反映(尚未),仍然说“键和值以非随机的任意顺序迭代”。具有讽刺意味的是,collections.OrderedDict
文档提到了新行为:
在版本3.6中更改:接受PEP 468后,将保留传递给
OrderedDict
构造函数及其update()
方法的关键字参数的顺序。< / p>
这是一篇提到some more details about it的文章:
一个次要但有用的内部改进: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
答案 3 :(得分:0)
从python 3.7开始,这现在是字典的默认行为,这是3.6的实现细节,截至2018年6月已采用:')
dict对象的插入顺序保留性质已声明是Python语言规范的正式组成部分。