reverse真的会反转一个Python迭代器吗?

6 投票
3 回答
1283 浏览
提问于 2025-04-18 16:03

我可以在一个列表上创建一个反向迭代器:

list(reversed([0,1,2,3]))

[3, 2, 1, 0]

我想这只是从索引 len(...)-10 调用 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。

撰写回答