Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 265 – 按值排序字典

作者:
Grant Griffin <g2 at iowegian.com>
状态:
已拒绝
类型:
标准跟踪
创建:
2001年8月8日
Python 版本:
2.2
历史记录:


内容目录

摘要

此 PEP 建议对字典进行“按值排序”操作。主要好处在于为常见的 Python 习惯用法提供“内置”支持,这种习惯用法在当前形式下,初学者难以理解,所有用户实施起来都很麻烦。

BDFL 声明

此 PEP 已被拒绝,因为 Py2.4 的 sorted() 内置函数已在很大程度上满足了对它的需求。

>>> sorted(d.iteritems(), key=itemgetter(1), reverse=True)
[('b', 23), ('d', 17), ('c', 5), ('a', 2), ('e', 1)]

或仅针对键

sorted(d, key=d.__getitem__, reverse=True)
['b', 'd', 'c', 'a', 'e']

此外,Python 2.5 的 heapq.nlargest() 函数解决了仅查找几个最高值项目的常见用例。

>>> nlargest(2, d.iteritems(), itemgetter(1))
[('b', 23), ('d', 17)]

动机

字典的一种常见用法是通过在第一次出现时将 d[key] 的值设置为 1,然后在每次后续出现时递增值来计算出现次数。这可以通过几种不同的方式完成,但 get() 方法是最简洁的。

d[key] = d.get(key, 0) + 1

计算完所有出现次数后,所得字典的常见用法是按出现次数排序的顺序打印出现次数,通常是将最大值放在最前面。

这导致需要按值对字典的项目进行排序。在 Python 中执行此操作的规范方法是首先使用 d.items() 获取字典项目的列表,然后将每个项目的元组的顺序从 (键,值) 反转为 (值,键),然后对列表进行排序;由于 Python 根据元组的第一个项目对列表进行排序,因此 (反转的) 项目列表因此按值排序。如果需要,可以反转列表,然后将元组重新反转回 (键,值)。(但是,根据我的经验,反转的元组顺序对于大多数目的来说都很好,例如打印出列表。)

例如,给定一个出现次数计数:

>>> d = {'a':2, 'b':23, 'c':5, 'd':17, 'e':1}

我们可能会执行以下操作:

>>> items = [(v, k) for k, v in d.items()]
>>> items.sort()
>>> items.reverse()             # so largest is first
>>> items = [(k, v) for v, k in items]

结果为:

>>> items
[('b', 23), ('d', 17), ('c', 5), ('a', 2), ('e', 1)]

这显示了按值排序的列表,最大值排在最前面。(在本例中,'b' 被发现出现次数最多。)

这可以正常工作,但在两个方面“难以使用”。首先,尽管这种习惯用法为经验丰富的 Python 开发人员所熟知,但对于新手来说却一点也不明显——无论是从其算法(反转项目元组的顺序)还是其实现(使用列表推导式——这是一种高级 Python 功能)的角度来看。其次,它需要反复键入大量“冗余代码”,导致乏味且容易出错。

因此,我们宁愿 Python 提供一种按值排序字典的方法,这种方法既易于初学者理解(或者,更好的是,不必理解),又易于所有人使用。

基本原理

正如 Tim Peters 指出,这种事情带来了试图满足所有人需求的问题。因此,我们将限制其范围以尝试找到“最佳点”。当然,可以使用当前方法“手动”处理不常见的情况(例如通过自定义比较函数进行排序)。

以下是一些简单的可能性:

字典的 items() 方法可以添加新的参数,这些参数具有提供完全向后兼容性的默认值。

(1) items(sort_by_values=0, reversed=0)

或者可能只是:

(2) items(sort_by_values=0)

因为反转列表非常容易。

或者,items() 可以简单地让我们控制 (键,值) 顺序。

(3) items(values_first=0)

同样,这是完全向后兼容的。它比其他方法的工作量少,但至少可以简化按值排序问题中最复杂/最棘手的部分:反转项目元组的顺序。使用它非常简单:

items = d.items(1)
items.sort()
items.reverse()         # (if desired)

前面三种方法的主要缺点是,由于必须处理默认参数,因此无参数的 items() 案例会产生额外的开销。(但是,如果假设 items() 主要用于创建按值排序的列表,那么在实践中这并不是真正的缺点。)

或者,我们可以添加一个新的字典方法,该方法以某种方式体现“排序”。这种方法有两个优点。首先,它避免了向 items() 方法添加开销。其次,它可能更容易被初学者接受:当他们寻找排序字典的方法时,希望他们能遇到这个方法,并且他们不必理解元组反转和列表排序的细节即可实现按值排序。

为了允许按键/值排序以及正向/反向排序的四种基本可能性,我们可以添加此方法:

(4) sorted_items(by_value=0, reversed=0)

我相信最常见的情况实际上是 by_value=1, reversed=1,但此处给出的默认值可能会导致用户遇到更少的意外情况:sorted_items() 将与 items() 后跟 sort() 相同。

最后(作为最后的手段),我们可以使用:

(5) items_sorted_by_value(reversed=0)

实现

建议的字典方法必须在 C 中实现。大概,实现将非常简单,因为它只涉及向 Python 的现有机制添加一些调用。

问题

除了已经在可能性 1 到 3 中解决的运行时开销外,此提案的疑虑可能将归类为“功能膨胀”和/或“代码膨胀”。但是,我相信此处提出的几个建议将导致非常小的膨胀,从而在膨胀和“增值”之间取得良好的平衡。

Tim Peters 已经注意到,在 C 中实现它可能不会比在今天的 Python 中实现它快得多。但是,此处预期的主要好处是“可访问性”和“易用性”,而不是“速度”。因此,只要它不会明显变慢(在普通 items() 的情况下,速度不必考虑)。

参考文献

一个相关的名为“计算出现次数”的主题出现在 2001 年 8 月的 comp.lang.python 上。这包括将按值排序问题系统化为可重用 Python 函数和类的示例方法。


来源:https://github.com/python/peps/blob/main/peps/pep-0265.rst

上次修改:2023-09-09 17:39:29 GMT