¿Puedo obtener las variables locales de una función de Python desde la que se lanzó una excepción?

Estoy escribiendo un sistema de registro personalizado para un proyecto. Si una función lanza una excepción, quiero registrar sus variables locales. ¿Es posible acceder a las variables locales de la función de subida desde el bloque de excepción que detectó la excepción? Por ejemplo:

def myfunction(): v1 = get_a_value() raise Exception() try: myfunction() except: # can I access v1 from here? 

En general, es un diseño más limpio para pasar el valor a la excepción, si sabe que su código de manejo de excepciones lo va a necesitar. Sin embargo, si está escribiendo un depurador o algo así, donde tendrá que acceder a las variables sin saber cuáles están por adelantado, puede acceder a una variable arbitraria en el contexto donde se lanzó la excepción:

 def myfunction(): v1 = get_a_value() raise Exception() try: myfunction() except: # can I access v1 from here? v1 = inspect.trace()[-1][0].f_locals['v1'] 

La funcionalidad de la función de trace y el formato de los objetos de traceback que trata, se describen en la documentación del módulo de inspect .

 def myFunction() v1 = get_a_value() raise Exception(v1) try: myFunction() except Exception, e: v1 = e.args[0] 

Puede buscar las variables locales en el objeto de marco, que puede obtener de sys.exc_info .

 >>> import sys >>> def f(a): ... b = a - 1 ... print 1.0 / b ... >>> try: ... f(1) ... except Exception, e: ... print sys.exc_info()[2].tb_next.tb_frame.f_locals ... {'a': 1, 'b': 0} 

Tendrá que incluir el número apropiado de tb_next s dependiendo de la profundidad de la stack en la que se lanzó la excepción.

Sí, si es tu propio tipo de excepción. Me gusta esto:

 >>> class MyExn(Exception): ... def __init__(self, val): ... self.val = val ... def __str__(self): ... print "something wrong with:", str(self.val) ... >>> def foo(): ... val = 42 ... raise MyExn(val) ... >>> foo() Traceback (most recent call last): File "", line 1, in  File "", line 3, in foo __main__.MyExnsomething wrong with: 42 >>> # Or in a try block: >>> try: ... foo() ... except MyExn as e: ... print e.val ... 42 >>> 
 try: myfunction() except: import sys type, value, tb = sys.exc_info() while tb.tb_next: tb = tb.tb_next frame = tb.tb_frame print frame.f_locals['v1']