PEP 281 – 使用 range 和 xrange 进行循环计数迭代
- 作者:
- Magnus Lie Hetland <magnus at hetland.org>
- 状态:
- 已拒绝
- 类型:
- 标准跟踪
- 创建:
- 2002年2月11日
- Python 版本:
- 2.3
- 历史记录:
摘要
本 PEP 描述了另一种在 for 循环中公开循环计数器的方法。它基本上建议将 PEP 212 中 indices()
函数的功能包含在现有的 range()
和 xrange()
函数中。
声明
在评论 PEP 279 的 enumerate()
函数时,本 PEP 的作者提出:“我很乐意让它使 PEP 281 过时。”随后,PEP 279 被纳入 Python 2.3。
2005年6月17日,BDFL 认为它已过时,并据此拒绝了该 PEP。为记录在案,他发现其中一些示例的外观有些刺眼。
>>> range(range(5), range(10), range(2))
[5, 7, 9]
动机
通常需要遍历序列的索引。PEP 212 描述了几种执行此操作的方法,包括添加一个名为 indices 的内置函数,概念上定义为
def indices(sequence):
return range(len(sequence))
假设向现有内置函数添加功能可能比添加新的内置函数侵入性更小,因此本 PEP 建议将此功能添加到现有的 range()
和 xrange()
函数中。
规范
建议允许内置函数 range()
和 xrange()
的所有三个参数都是具有长度的对象(即实现 __len__
方法的对象)。如果参数无法解释为整数(即它没有 __int__
方法),则将使用其长度代替。
示例
>>> range(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(range(5), range(10))
[5, 6, 7, 8, 9]
>>> range(range(5), range(10), range(2))
[5, 7, 9]
>>> list(xrange(range(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(xrange(xrange(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Number the lines of a file:
lines = file.readlines()
for num in range(lines):
print num, lines[num]
替代方案
上述规范的自然替代方案是允许 xrange()
以惰性方式访问其参数。因此,xrange
可以不显式地使用它们的长度,而是为停止参数的每个元素返回一个索引,直到到达末尾。对于开始和步长参数,类似的惰性处理没有多大意义,因为必须在迭代开始之前计算它们的长度。(实际上,直到返回第二个元素之前,才需要步长参数的长度。)
伪实现(仅使用停止参数,并假设它是可迭代的)如下:
def xrange(stop):
i = 0
for x in stop:
yield i
i += 1
可以通过检查 __iter__
属性来测试是否使用 int()
或惰性迭代。(此示例假设存在生成器,但可以很容易地实现为普通迭代器对象。)
此功能是否真正有用可能值得怀疑,因为无法通过索引在 for 循环内访问可迭代对象的元素。
示例
# Printing the numbers of the lines of a file:
for num in range(file):
print num # The line itself is not accessible
一个更有争议的替代方案(来解决这个问题)是让 range()
在提供序列时表现得像 PEP 212 中的 irange()
函数一样。
示例
>>> range(5)
[0, 1, 2, 3, 4]
>>> range('abcde')
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
向后兼容性
如果使用同时实现 __int__
和 __len__
(或在 xrange
的惰性迭代情况下为 __iter__
)的参数,则该提案可能会导致向后不兼容。作者认为这不是一个严重的问题。
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0281.rst