¿Qué tipo de mensaje es “Excepción ignorada en”?

Aquí está el código:

def g(): try: yield 1 yield 2 yield 3 except GeneratorExit: yield 4 gen = g() print(gen.__next__()) 

Si lo ejecutas verás:

 1 Exception ignored in:  RuntimeError: generator ignored GeneratorExit 

Entiendo lo que sucedió, pero no puedo encontrar qué tipo de mensaje es esta advertencia.

Parece que no es una advertencia de logging (no puedo eliminarlo configurando el nivel de registro). Tampoco es una warnings advertencia (no se parece a lo que recibimos cuando llamamos warnings.warn ).

Pensé que se puede asociar con una excepción, pero no puedo atraparlo con sys.excepthook , mientras que el sys.excepthook desaparece:

 import sys def hook(exc_type, exc_val, tb): print(exc_type, exc_val, tb) # Nothing prints, while msg disappear sys.excepthook = hook 

¿Cómo puedo captar esta advertencia?

¿Cómo puedo crear manualmente este tipo de advertencia?

Como algunos han señalado, no todos reciben siempre el comportamiento que usted describe. Por ejemplo, no obtendrá este comportamiento en el REPL. Para reproducir este comportamiento en el REPL tienes que agregar del gen al final. Esto nos permite saber de dónde viene la advertencia. La advertencia proviene de la función de limpieza del objeto generador, que ha notado que el generador no ha salido limpiamente.

Lo que ha ocurrido específicamente es que el generador ha generado una excepción mientras el intérprete está intentando limpiar el generador y liberar sus recursos. El intérprete no tiene forma de propagar esta excepción de nuevo, por lo que, en cambio, registra este estado y continúa. Específicamente, se está llamando a PyErr_WriteUnraisable . Y aquí está cómo se llama (los comentarios son míos).

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

cuando ejecuto tu código acabo de obtener:

 1 >>> 

sin error (yo también uso Python 3.5.1 en Windows 10), pero puedes usar el siguiente código para determinar el error en tu código:

 try: a = int('a') # here you can put your code except Exception as e: print(e) # this prints error message print(type(e).__name__) # this prints name of your error 

En este caso obtienes esta salida:

 invalid literal for int() with base 10: 'a' ValueError >>> 

así que para atrapar el error ahora puedes usar:

 to_convert = 'a' try: a = int(to_convert) except ValueError: print(to_convert, 'can\'t be converted to string.') 

Al observar su mensaje de error, creo que tiene un problema con RuntimeError y no con GeneratorExit .

Espero eso ayude.

Editar:

Como @interjay dijo en los comentarios cuando ejecuté el generador de código, el objeto no se destruyó al final, por lo que no hubo ningún error.

El problema es cuando Python destruye el objeto generador, se llama a generator.close() que produce su error, cuando ejecuta este código:

 def g(): try: yield 1 yield 2 yield 3 except GeneratorExit: yield 4 gen = g() print(gen.__next__()) gen.close() 

usted obtiene:

 RuntimeError: generator ignored GeneratorExit >>> 

pero cuando el objeto generador se destruye (elimina), la excepción se ignora.

Para evitar esta advertencia, puede llamar a generator.close() en su código y luego detectar el error, por lo que su código debería tener este aspecto:

 def g(): try: yield 1 yield 2 yield 3 except GeneratorExit: yield 4 gen = g() print(gen.__next__()) try: gen.close() except RuntimeError: pass