所以我可以在列表上创建一个反向迭代器:
list(reversed([0,1,2,3]))
[3, 2, 1, 0]
我认为这只是将getitem
从索引len(...)-1
调用到0
。但是我不能这样做:
list(reversed(xrange(4)))
[3, 2, 1, 0]
现在我有点困惑。这是否会从xrange(4)
创建列表然后反转它?如果没有,它如何知道最后一个元素是什么以及如何倒退?我看了documentation,但没有帮助。
答案 0 :(得分:8)
reversed()
在对象上查找__reversed__
special method。列表对象提供了这一点,xrange()
:
>>> xrange(4).__reversed__()
<rangeiterator object at 0x106e2fa50>
迭代器对象只是反向生成值,不生成列表对象。
对于不实现__reversed__
的对象,reversed()
函数使用长度和__getitem__
方法;例如reversed()
基本上等同于:
def reversed(seq):
try:
return seq.__reversed__()
except AttributeError:
return (seq[i] for i in xrange(len(seq) - 1, -1 , -1))
其中第二部分是生成器表达式,懒惰地进行评估。然后,生成器依次从索引(长度 - 1)开始一直访问每个项目,直到索引0。
答案 1 :(得分:4)
reversed()
只能接受一个序列 - 如果它采用了泛型迭代器,它就不会知道最终值是什么而不会耗尽迭代器并存储所有值。
幸运的是,xrange
返回一个xrange对象作为序列:
>>> x = xrange(10)
>>> len(x)
10
>>> x[9]
9
它也恰好有一个实际的__reversed__
方法,但这是一个拥有所有序列方法的特例。
答案 2 :(得分:1)
比较两者:
In [2]: reversed(xrange(4))
Out[2]: <rangeiterator at 0x7fa83291bde0>
In [3]: list(reversed(xrange(4)))
Out[3]: [3, 2, 1, 0]
In [4]: reversed([0,1,2,3])
Out[4]: <listreverseiterator at 0x7fa8328be2d0>
In [5]: list(reversed([0,1,2,3]))
Out[5]: [3, 2, 1, 0]