这是代码:
def g():
try:
yield 1
yield 2
yield 3
except GeneratorExit:
yield 4
gen = g()
print(gen.__next__())
如果运行它,将会看到:
1
Exception ignored in: <generator object g at 0x00000216BB546A98>
RuntimeError: generator ignored GeneratorExit
我了解发生了什么,但是我找不到此警告是哪种类型的消息。
看起来这不是
logging
警告(我无法在设置日志记录级别时将其删除)。这也不是warnings
警告(看起来不像我们调用warnings.warn
时得到的警告)。我以为它可以与异常关联,但是我无法用
sys.excepthook
捕获它,而msg本身消失了:import sys
def hook(exc_type, exc_val, tb):
print(exc_type, exc_val, tb) # Nothing prints, while msg disappear
sys.excepthook = hook
我怎么能得到这个警告?
如何手动创建此类警告?
最佳答案
正如某些人指出的那样,并非每个人都总是得到您描述的行为。例如,您不会在REPL上获得此行为。要在REPL上重现此行为,您必须在末尾添加del gen
。这使我们知道警告即将到来。该警告来自生成器对象的清除功能,该功能已注意到生成器未完全退出。
具体发生的是,在解释器尝试清理生成器并释放其资源时,生成器引发了异常。解释器无法传播此异常,因此它将记录此状态并继续执行。具体而言,正在调用PyErr_WriteUnraisable。 here是它的称呼方式(我的评论)。
void
_PyGen_Finalize(PyObject *self)
{
...
if (gen is a coroutine) {
// special error detecting logic for coroutines
}
else {
res = gen_close(gen, NULL); // <- raises GeneratorExit
}
if (res == NULL) {
if (PyErr_Occurred()) {
PyErr_WriteUnraisable(self);
}
}
else {
Py_DECREF(res);
}
...
}