找到你要的答案

Q:python reverse iterator vs. generator behavior

Q:Python的反向迭代器与发电机的行为

Why does removing items a list break reversed objects? It doesn't break gen-exprs, and appending to or modifying the list doesn't break the reversed object, and it obviously points to the original object, so why can't it give a truncated version? Perhaps some examples can clarify:

l = [1, 2, 3, 4]
r = reversed(l)
g = (i for i in l)
l.pop()  # returns 4
l   # returns [1, 2, 3]

for i in g:print(i)  # prints 1 2 3 (on separate lines)
for i in r:print(i)  # prints ...nothing

r = reverse(l)
g = (i for i in l)
l[1] = 4
for i in g:print(i)  # prints 1 4 3 (on separate lines)
for i in r:print(i)  # prints 3 4 1 (on separate lines)

r = reversed(l)
g = (i for i in l)
l.append(5)
l  # returns [1, 4, 3, 5] just to keep you on your toes

for i in g:print(i)  # prints 1 4 3 5 (on separate lines)
for i in r:print(i)  # prints 3 4 1   (on separate lines)

So - if the genexpr is smart enough to point to the object, and just respond to however the object has changed, why doesn't reversed? It obviously doesn't make a copy, otherwise it wouldn't "fail" on the first situation, and it wouldn't pick up the 4 in the second. So it must point to the object. Why can't it just start from index -1 and work backwards?

为什么删除列表中的条目会中断反向对象?它不断创exprs,添加或修改列表不打破颠倒对象,它显然指向原来的对象,那么为什么不能给截断版本吗?也许一些例子可以澄清:

l = [1, 2, 3, 4]
r = reversed(l)
g = (i for i in l)
l.pop()  # returns 4
l   # returns [1, 2, 3]

for i in g:print(i)  # prints 1 2 3 (on separate lines)
for i in r:print(i)  # prints ...nothing

r = reverse(l)
g = (i for i in l)
l[1] = 4
for i in g:print(i)  # prints 1 4 3 (on separate lines)
for i in r:print(i)  # prints 3 4 1 (on separate lines)

r = reversed(l)
g = (i for i in l)
l.append(5)
l  # returns [1, 4, 3, 5] just to keep you on your toes

for i in g:print(i)  # prints 1 4 3 5 (on separate lines)
for i in r:print(i)  # prints 3 4 1   (on separate lines)

所以,如果genexpr是足够聪明点的对象,只是回应但是对象变了,为什么不反?它显然不复制,否则它不会“失败”的第一个情况,它不会拿起第二个4。所以它必须指向对象。为什么不能从指数1开始并向后工作?

answer1: 回答1:

When you call reversed() on a list object, a dedicated reverse list iterator object is created; this object 'knows' how to efficiently iterate over the list in reverse order once.

To do this, when the object is created the last index in the list is stored. For your list l, that is 3 (the 4th element, counting from 0). When you then iterate, the element at that index is yielded, and the index is decremented, until an IndexError is raised *.

A Python implementation of the object would look like this:

class reversed_list_iterator(object):
    def __init__(self, lst):
        self.index = len(lst) - 1
        self.lst = lst

    def __iter__(self):
        return self

    def __next__(self):
        try:
            result = self.lst[self.index]
        except IndexError:
            self.lst = []  # switch to permanently stopped state
            raise StopIteration
        self.index -= 1
        return result

Now, when you then remove that element, the iterator exits as there is no l[3], an IndexError is raised there and then and iteration ends.

In your second example, when creating the reversed iterator, the last index is 2. You then add to the list, but iteration starts at l[2], which still exists.

The reversed list iterator cannot use relative indices, because as you discovered, the iterator is relatively tolerant of elements being added to the list. A relative index would then repeat values.


* The actual C implementation tests for the boundaries 0 <= index < len(self.lst) rather than catch IndexError, but the principle is the same.

当你打电话reversed()列表上的对象,一个专门的反向列表迭代器对象被创建;这个对象知道如何有效地遍历次序颠倒一次列表。

为此,当创建对象时,将存储列表中的最后一个索引。对于您的列表L,即3(第四元素,计算从0)。当你进行迭代,在索引的元素产生,与指数递减,直到一个误差系数提高*。

一个对象的Python实现这个样子:

class reversed_list_iterator(object):
    def __init__(self, lst):
        self.index = len(lst) - 1
        self.lst = lst

    def __iter__(self):
        return self

    def __next__(self):
        try:
            result = self.lst[self.index]
        except IndexError:
            self.lst = []  # switch to permanently stopped state
            raise StopIteration
        self.index -= 1
        return result

现在,当你再删除元素的迭代器的存在,没有我的[ 3 ],一个误差系数是在那里长大然后迭代结束。

在第二个示例中,当创建反向迭代器时,最后一个索引是2。然后,您添加到列表中,但迭代开始在L [ 2 ],仍然存在。

反向列表迭代器不能使用相对索引,因为正如您所发现的那样,迭代器对添加到列表中的元素比较宽容。相对索引将重复值。


*实际的C实现测试的界限0 & lt;=指数<;len(自我。LST)而不是抓误差系数,但原理是相同的。

python  python-3.x  iterator  generator  reverse