我查看了内置python异常的层次结构,并注意到StopIteration
和GeneratorExit
具有不同的基类:
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
+-- Warning
或在代码中:
>>> GeneratorExit.__bases__
(<type 'exceptions.BaseException'>,)
>>> StopIteration.__bases__
(<type 'exceptions.Exception'>,)
当我转到每个异常的具体描述时,我可以阅读以下内容:
https://docs.python.org/2/library/exceptions.html#exceptions.GeneratorExit
https://docs.python.org/2/library/exceptions.html#exceptions.StopIteration
这对我来说不是很清楚。从它们不通知错误的意义上来说,两者是相似的,而是改变代码流的“事件”。因此,从技术上讲它们不是错误,并且我知道应该将它们与其余的异常分开……但是为什么一个是
BaseException
的子类,而另一个是Exception
的子类呢?通常,我一直认为
Exception
子类是错误,并且当我编写盲目try: except:
(例如,调用第三方代码)时,我总是 try catch Exception
,但是也许那是错误的,我应该捕获StandardError
。 最佳答案
通常使用try:...,但Exception:...块除外。
如果GeneratorExit将从Exception继承,则会出现以下问题:
def get_next_element(alist):
for element in alist:
try:
yield element
except BaseException: # except Exception
pass
for element in get_next_element([0,1,2,3,4,5,6,7,8,9]):
if element == 3:
break
else:
print(element)
0
1
2
Exception ignored in: <generator object get_next_element at 0x7fffed7e8360>
RuntimeError: generator ignored GeneratorExit
这个例子很简单,但是想像一下try块中一个更复杂的操作,如果失败,它将简单地忽略问题(或打印一条消息)并进入下一个迭代。
如果捕获到通用的Exception,最终将阻止生成器的用户中断循环而没有得到RuntimeError。
更好的解释是here。
编辑:在这里回答,因为评论太久了。
我宁愿相反。
GeneratorExit
应该继承自Exception
而不是BaseException
。当您捕获Exception
时,您基本上想捕获几乎所有内容。 BaseException
如PEP-352所述,用于需要“异常(exception)”的那些异常(exception),以便允许用户从否则会捕获它们的代码中逃脱。这样,您可以,例如,仍然CTRL-C运行代码。 GeneratorExit
属于该类别,以便打破循环。在comp.lang.python上有趣的对话。