reverse真的会反转一个Python迭代器吗?
我可以在一个列表上创建一个反向迭代器:
list(reversed([0,1,2,3]))
[3, 2, 1, 0]
我想这只是从索引 len(...)-1
到 0
调用 getitem
。但是我不能这样做:
list(reversed(xrange(4)))
[3, 2, 1, 0]
现在我有点困惑。这是先从 xrange(4)
创建列表,然后再反转吗?如果不是,它是怎么知道最后一个元素是什么,以及如何往回走的?我看了文档,但没帮上忙。
3 个回答
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]
4
reversed()
这个函数只能处理序列类型的数据。如果它能处理普通的迭代器,那就没办法知道最后的值是什么,因为它需要把迭代器里的所有值都取出来才能知道。
幸运的是,xrange
返回的是一个 xrange 对象,这个对象可以当作序列来用:
>>> x = xrange(10)
>>> len(x)
10
>>> x[9]
9
而且它实际上还有一个 __reversed__
方法,不过这只是它拥有所有序列方法的一个特殊情况。
9
reversed()
这个函数会在对象上查找一个叫做 __reversed__
的特殊方法。列表对象是有这个方法的,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。