2

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 设计中像这样填充表格单元格是否有意义?是否有任何特殊原因尚未实施?

4

4 回答 4

17

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

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

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

于 2012-11-13T03:56:53.277 回答
4

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

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

PHP 风格的数组不是这些东西。它们不是快速或轻量级的,运行时复杂性定义不明确,而且它们的语义很混乱,因为它们可以用于许多不同的事情——看看数组函数。对于几乎所有用例来说,它们实际上都是一种糟糕的数据类型,除了创建它们的非常狭窄的用例:表示x-www-form-encoded数据。即使对于这个用例,一个失败是早期的键会覆盖后面键的值:在 PHP?a=1&a=2中会导致array('a'=>2). (在 Python 中处理这个问题的一个常见结构是MultiDict,它有有序的键值,每个键可以有多个值。)

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

于 2012-11-13T04:16:18.063 回答
1

添加带有更新信息的新答案:从C Python3.6 开始,dicts保留 order。虽然仍然不能索引访问。很可能是因为基于整数的项目查找不明确,因为 dict 键可以是 int 的。(存在一些自定义用例。)

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

在 3.6 版更改: 随着PEP 468OrderedDict的接受,传递给构造函数及其update()方法的关键字参数的顺序被保留。

这是一篇文章,其中提到了有关它的更多详细信息

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

因此,如果您只为 Py36 及更高版本编写代码,collections.OrderedDict除非您使用或基于顺序的相等性popitem,否则您不应该需要。move_to_end

例如,在 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
于 2017-01-16T18:33:58.720 回答
0

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

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

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

于 2018-08-13T17:19:11.567 回答