为什么 GeneratorExit 和 StopIteration 的基数不同 类?
Why do GeneratorExit and StopIteration have different base classes?
我查看了内置 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
exception GeneratorExit
Raised when a generator‘s close() method is called. It directly inherits from BaseException instead of StandardError since it is technically not an error.
https://docs.python.org/2/library/exceptions.html#exceptions.StopIteration
exception StopIteration
Raised by an iterator‘s next() method to signal that there are no further values. This is derived from Exception rather than StandardError, since this is not considered an error in its normal application.
我不是很清楚。两者的相似之处在于它们不通知错误,而是 "event" 来更改代码流。所以,它们在技术上不是错误,我知道它们应该与其他异常分开......但为什么一个是 BaseException
的子类,另一个是 Exception
的子类? .
总的来说,我总是认为 Exception
sub类 是错误的,当我写一个盲目的 try: except:
(例如调用第三方代码)时,我总是试图抓住Exception
,但也许这是错误的,我应该抓住 StandardError
。
使用 try: ... except 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 块中有一个更复杂的操作,如果失败,将简单地忽略问题(或打印消息)并进入下一个迭代。
如果您要捕获通用异常,您最终会阻止生成器的用户在没有得到 RuntimeError 的情况下中断循环。
更好的解释是here。
编辑:因为评论太长,所以在这里回答。
我宁愿说相反的话。 GeneratorExit
应该继承自 Exception
而不是 BaseException
。当你捕捉 Exception
时,你基本上想要捕捉几乎所有的东西。 BaseException
作为 PEP-352 states, is for those exceptions which need to be "excepted" in order to allow the user to escape from code that would otherwise catch them. In this way you can, for example, still CTRL-C running code. GeneratorExit
falls into that category in order to break loops. An interesting conversation about it on comp.lang.python.
我自己来这里寻找答案,在别处找到了。
有 3 个“特殊”异常直接继承自 BaseException 而不是 Exception:
SystemExit
KeyboardInterrupt
GeneratorExit
这 3 个在概念上不同于“正常异常”。它们不是错误,而是您可能不想捕获的意外外部事件。你期望退出。终止,停止!
SystemExit 和 KeyboardInterrupt 很明显。 sys.exit() 生成一个 SystemExit,ctrl-C 一个 KeyboardInterrupt
GeneratorExit 会杀死一个在被删除时没有完全迭代的生成器或垃圾collected.But只有生成器会死掉而不是整个程序。
那么 StopIteration 呢?这也不是错误。嗯,有点像。您要求下一个,但没有下一个。而且它显然必须被抓住。否则任何 for 循环都会产生一个退出。
将其称为错误似乎有点不公平,因为等待它是确定循环结束的唯一方法。但残酷的官僚主义:你要求的是你得不到的东西。这是一个错误。
我查看了内置 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
exception GeneratorExit
Raised when a generator‘s close() method is called. It directly inherits from BaseException instead of StandardError since it is technically not an error.
https://docs.python.org/2/library/exceptions.html#exceptions.StopIteration
exception StopIteration
Raised by an iterator‘s next() method to signal that there are no further values. This is derived from Exception rather than StandardError, since this is not considered an error in its normal application.
我不是很清楚。两者的相似之处在于它们不通知错误,而是 "event" 来更改代码流。所以,它们在技术上不是错误,我知道它们应该与其他异常分开......但为什么一个是 BaseException
的子类,另一个是 Exception
的子类? .
总的来说,我总是认为 Exception
sub类 是错误的,当我写一个盲目的 try: except:
(例如调用第三方代码)时,我总是试图抓住Exception
,但也许这是错误的,我应该抓住 StandardError
。
使用 try: ... except 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 块中有一个更复杂的操作,如果失败,将简单地忽略问题(或打印消息)并进入下一个迭代。
如果您要捕获通用异常,您最终会阻止生成器的用户在没有得到 RuntimeError 的情况下中断循环。
更好的解释是here。
编辑:因为评论太长,所以在这里回答。
我宁愿说相反的话。 GeneratorExit
应该继承自 Exception
而不是 BaseException
。当你捕捉 Exception
时,你基本上想要捕捉几乎所有的东西。 BaseException
作为 PEP-352 states, is for those exceptions which need to be "excepted" in order to allow the user to escape from code that would otherwise catch them. In this way you can, for example, still CTRL-C running code. GeneratorExit
falls into that category in order to break loops. An interesting conversation about it on comp.lang.python.
我自己来这里寻找答案,在别处找到了。 有 3 个“特殊”异常直接继承自 BaseException 而不是 Exception:
SystemExit
KeyboardInterrupt
GeneratorExit
这 3 个在概念上不同于“正常异常”。它们不是错误,而是您可能不想捕获的意外外部事件。你期望退出。终止,停止!
SystemExit 和 KeyboardInterrupt 很明显。 sys.exit() 生成一个 SystemExit,ctrl-C 一个 KeyboardInterrupt
GeneratorExit 会杀死一个在被删除时没有完全迭代的生成器或垃圾collected.But只有生成器会死掉而不是整个程序。
那么 StopIteration 呢?这也不是错误。嗯,有点像。您要求下一个,但没有下一个。而且它显然必须被抓住。否则任何 for 循环都会产生一个退出。
将其称为错误似乎有点不公平,因为等待它是确定循环结束的唯一方法。但残酷的官僚主义:你要求的是你得不到的东西。这是一个错误。