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 不会显式使用它们的长度,而是可以为 stop 参数的每个元素返回一个索引,直到到达末尾。类似的惰性处理对于 start 和 step 参数意义不大,因为它们的长度必须在迭代开始之前计算。(实际上,step 参数的长度直到返回第二个元素才需要。)
一个伪实现(仅使用 stop 参数,并假设它是可迭代的)是
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