How yield catches StopIteration exception?
示例函数终止的原因:
1 2 3 4 | def func(iterable): while True: val = next(iterable) yield val |
但如果我去掉yield语句函数,会引发stopIteration异常吗?
编辑:很抱歉误导你们。我知道发电机是什么以及如何使用它们。当然,当我说函数终止时,我并不是说要对函数进行急切的评估。我只是暗示,当我使用函数生成生成器时:
1 | gen = func(iterable) |
在func的情况下,它工作并返回相同的生成器,但在func2的情况下:
1 2 3 | def func2(iterable): while True: val = next(iterable) |
它将引发StopIteration,而不是无返回或无限循环。
让我更具体一点。itertools中有一个函数tee,相当于:
1 2 3 4 5 6 7 8 9 10 11 | def tee(iterable, n=2): it = iter(iterable) deques = [collections.deque() for i in range(n)] def gen(mydeque): while True: if not mydeque: # when the local deque is empty newval = next(it) # fetch a new value and for d in deques: # load it to all the deques d.append(newval) yield mydeque.popleft() return tuple(gen(d) for d in deques) |
实际上,有一些魔力,因为嵌套函数gen具有无限的不带break语句的循环。当函数中没有任何项时,由于StopIteration异常,Gen函数将终止。但它正确地终止(不引发异常),即只停止循环。所以问题是:StopIteration在哪里处理?
要回答您的问题,关于
首先,需要注意的是,生成器函数(在任何地方都是带有
生成器函数不会在不提升
这与常规函数不同,后者返回
下面是一个示例生成器函数,可以很容易地看到
1 2 3 4 | def simple_generator(): yield"foo" yield"bar" # StopIteration will be raised here automatically |
以下是当你消费它时会发生的事情:好的。
1 2 3 4 5 6 7 8 9 10 | >>> g = simple_generator() >>> next(g) 'foo' >>> next(g) 'bar' >>> next(g) Traceback (most recent call last): File"<pyshell#6>", line 1, in <module> next(g) StopIteration |
调用
现在,通常您不会看到
像
1 2 3 4 5 6 7 8 9 | iterator = iter(iterable) try: while True: item = next(iterator) do_stuff(item) except StopIteration: pass finally: del iterator |
您在顶部显示的
与主要问题无关,还有一件事我想指出。在代码中,您在一个名为
编辑:我刚刚在谷歌搜索相关问题时找到了自己的答案,我想我应该更新一下,指出上面的答案在将来的Python版本中不会完全正确。PEP479使得允许
这意味着需要修改类似于
因为这是一个向后不兼容的变化,它正逐渐被逐步采用。在python 3.5中,默认情况下,所有代码都将像以前一样工作,但是您可以使用
型
当函数包含
考虑到你的功能和一个不可替代的:
1 2 3 4 5 6 | def func(iterable): while True: val = next(iterable) yield val iterable = iter([1, 2, 3]) |
这是错误的称呼:
1 | func(iterable) |
。
这是正确的方法:
1 2 | for item in func(iterable): # do something with item |
您还可以将生成器存储在变量中,并对其调用
1 2 3 4 5 | gen = func(iterable) print(next(gen)) # prints 1 print(next(gen)) # prints 2 print(next(gen)) # prints 3 print(next(gen)) # StopIteration |
。
顺便说一下,编写函数的更好方法如下:
1 2 3 | def func(iterable): for item in iterable: yield item |
。
或者在python 3.3及更高版本中:
1 2 | def func(iterable): yield from iter(iterable) |
当然,真正的发电机很少如此微不足道。:-)
型
如果没有
1 2 3 | def func(iterable): for val in iterable: pass |
它确实捕获了
您可以显式捕获异常:
1 2 3 4 5 6 | def func(iterable): while True: try: val = next(iterable) except StopIteration: break |
号
型
考虑:
1 2 | x = func(x for x in []) next(x) #raises StopIteration |
。
一个