Sé que, en general, Python solo crea nuevos ámbitos para clases, funciones, etc., pero estoy confundido por la declaración as en un bloque try/except o administrador de contexto. Las variables asignadas dentro del bloque son accesibles fuera de él, lo que tiene sentido, pero la variable vinculada as sí misma no lo es.
Entonces esto falla:
try: raise RuntimeError() except RuntimeError as error: pass print(repr(error))pero esto tiene éxito:
try: raise RuntimeError() except RuntimeError as e: error = e print(repr(error)) ¿Qué sucede con la variable enlazada con as y por qué no se aplican las reglas normales de alcance de Python? El PEP indica que es solo una variable de python normalmente enlazada, pero ese no parece ser el caso.
Esta es una excepción documentada a las reglas normales que *se aplica específicamente a las sentencias try-except , de la referencia del lenguaje :
Cuando se ha asignado una excepción usando como objetivo, se borra al final de la cláusula de excepción. Esto es como si:
except E as N: foofue traducido a
except E as N: try: foo finally: del NEsto significa que la excepción debe asignarse a un nombre diferente para poder hacer referencia a ella después de la cláusula de excepción. Las excepciones se eliminan porque, con el rastreo adjunto, forman un ciclo de referencia con el marco de la pila, lo que mantiene vivos todos los locales en ese marco hasta que se produzca la próxima recolección de elementos no utilizados.
Como se señaló, la razón por la que esto ocurre es para evitar ciclos de referencia.
Tenga en cuenta que esto solo se aplica a una declaración compuesta try - except , as que no es una declaración independiente, es parte de declaraciones compuestas diferentes e independientes ( with y try-except )
Como se explica en PEP 3110 , así como en la documentación actual , las variables enlazadas con as en un bloque de except se borran explícita y especialmente al final del bloque, aunque comparten el mismo ámbito local. Esto mejora la inmediatez de la recolección de basura. Originalmente, la sintaxis as no estaba disponible para excepciones en 2.x; fue respaldado para 2.6 , pero se conservó la semántica anterior.
No ocurre lo mismo with los bloques with:
>>> from contextlib import contextmanager >>> @contextmanager ... def test(): ... yield ... >>> with test() as a: ... pass ... >>> a # contains None; does not raise NameError >>> >>> def func(): # similarly within a function ... with test() as a: ... pass ... return a ... >>> func() >>> El comportamiento es específico del bloque except , no de la palabra clave as .