这是代码:

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_WriteUnraisablehere是它的称呼方式(我的评论)。

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);
    }

    ...
}

10-06 15:47