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的内容时,它是未指定的,因此您不应该对不同的结果感到惊讶。一些迭代器可能会因错误而停止(字典迭代器会停止),而其他迭代器可能会提前退出(如您的问题所涉及的列表反向迭代器),或者跳过或重复元素。