Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python反向迭代器与生成器行为_Python_Python 3.x_Iterator_Generator_Reverse - Fatal编程技术网

python反向迭代器与生成器行为

python反向迭代器与生成器行为,python,python-3.x,iterator,generator,reverse,Python,Python 3.x,Iterator,Generator,Reverse,为什么删除列表中的项目会中断反向对象?它不会破坏gen exprs,添加或修改列表也不会破坏reversed对象,而且它显然指向原始对象,所以为什么不能给出一个截断的版本呢?也许一些例子可以澄清: 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 line

为什么删除列表中的项目会中断
反向
对象?它不会破坏gen exprs,添加或修改列表也不会破坏
reversed
对象,而且它显然指向原始对象,所以为什么不能给出一个截断的版本呢?也许一些例子可以澄清:

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
开始反向工作?

当您在列表对象上调用
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
现在,当您删除该元素时,迭代器将退出,因为没有
l[3]
,一个
索引器将在那里出现,然后迭代结束

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

反向列表迭代器不能使用相对索引,因为正如您所发现的,迭代器对添加到列表中的元素具有相对容忍度。然后,相对索引将重复这些值



*边界测试
0我想我的问题是:如果不是使用
len(l)
的硬编码,而是用硬编码的
-1
替换,效率是否会降低?@dwanderson:行为会改变,因为现在添加到列表中会改变迭代器移动到下一个位置。添加5个元素,你将迭代器设置回原来的值。嗯,好的,绝对正确。不过,我可以看出这是意料之中的行为。但是我想如果它有不这样做的历史,那可能会破坏一切。哦,关于C实现的有趣的旁注,感谢挖掘:)。但是看看它,
行2918
看起来好像在调用
next
时调用了
seq
的大小,这。。。哦,好的:它以
it\u index
作为原始
seq
长度开始,然后我缩短列表,这样
如果
失败,它会认为它是空的。这是有道理的,至少是为什么我看到了我的行为。@dwanderson:它检测到索引超出了范围(如果在Python代码中使用,将引发
索引器)。我非常确定Python迭代器的行为(包括
反向
迭代器)当您在迭代器运行时修改iterable的内容时,它是未指定的,因此您不应该对不同的结果感到惊讶。一些迭代器可能会因错误而停止(字典迭代器会停止),而其他迭代器可能会提前退出(如您的问题所涉及的列表反向迭代器),或者跳过或重复元素。