为什么删除项目列表中断reversed
个对象?它不会破坏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足够智能指向对象,只是响应对象已经改变,为什么不reversed
?它显然不会复制,否则它不会在第一种情况下“失败”,并且它不会在第二种情况下获得4
。所以它必须指向对象。为什么它不能从索引-1
开始并向后工作?
答案 0 :(得分:6)
当您在列表对象上调用reversed()
时,会创建一个专用的反向列表迭代器对象;这个对象'知道'如何以相反的顺序有效地迭代列表一次。
为此,在创建对象时,将存储列表中的最后一个索引。对于您的列表l
,即3
(第4个元素,从0开始计算)。然后迭代时,会生成该索引处的元素,并递减索引,直到IndexError
被引发 * 。
该对象的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]
,IndexError
被引发然后并且迭代结束。
在第二个示例中,创建反向迭代器时,最后一个索引为2
。然后添加到列表中,但迭代从l[2]
开始,仍然存在。
反向列表迭代器不能使用相对索引,因为正如您所发现的那样,迭代器相对容忍要添加到列表中的元素。然后,相对索引将重复值。
* actual C implementation测试边界0 <= index < len(self.lst)
而不是捕获IndexError
,但原理是相同的。