为什么这里没有抛出StopIteration?
看看这个问题,关键点在下面:
>>> scan = iter('FHUR203459')
>>> while True:
print(next(scan))
F
H
U
R
2
0
3
4
5
9
Traceback (most recent call last):
File "<pyshell#11>", line 2, in <module>
print(next(scan))
StopIteration
>>> scan = iter('FHUR203459')
>>> for i in range(12): # 12 * 2 for each join is 24, much longer than the string; should raise error.
print(''.join(next(scan) for i in range(2)))
FH
UR
20
34
59
>>>
换句话说,我们可以看到在这两种情况下,迭代器都到了尽头,但只有在第一种情况下会抛出一个 StopIteration
的错误,尽管在两种情况下都在到达尽头后使用了 next()
。为什么在 join
中使用它似乎没有出现这个错误?这算不算一个bug呢?
2 个回答
2
str.join()
方法会对生成器使用 list()
,而这个调用会忽略掉 StopIteration
这个异常。
任何 消耗 迭代器的操作 都必须 处理 StopIteration
;这时候究竟是什么引发了这个异常并不重要,可能是生成器表达式本身,或者是生成器表达式中使用的任何东西:
>>> def raises_stopiteration(): raise StopIteration
...
>>> next(raises_stopiteration() for _ in range(10))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <genexpr>
File "<stdin>", line 1, in raises_stopiteration
StopIteration
>>> list(raises_stopiteration() for _ in range(10))
[]
2
在第一个例子中,StopIteration
这个情况没有被处理。但是在第二个例子中,
''.join(next(scan) for i in range(2))
我们把一个 生成器表达式 传给了 ''.join
,这个方法会处理由 next(scan)
引发的 StopIteration
,并且每次都会正常退出。所以 ''.join
产生了空字符串。
你可以稍微修改一下,给 ''.join
传一个列表,然后自己看看会抛出异常,像这样
>>> scan = iter('FHUR203459')
>>> for i in range(12):
... print(''.join([next(scan) for i in range(2)]))
...
FH
UR
20
34
59
Traceback (most recent call last):
File "<input>", line 2, in <module>
File "<input>", line 2, in <listcomp>
StopIteration
这就表明 StopIteration
确实被抛出了,而这次是 列表推导式 遇到了问题。