【发布时间】:2012-01-30 04:28:01
【问题描述】:
我正在为一个项目编写自定义日志系统。如果一个函数抛出异常,我想记录它的局部变量。是否可以从捕获异常的异常块中访问引发函数的局部变量?例如:
def myfunction():
v1 = get_a_value()
raise Exception()
try:
myfunction()
except:
# can I access v1 from here?
【问题讨论】:
我正在为一个项目编写自定义日志系统。如果一个函数抛出异常,我想记录它的局部变量。是否可以从捕获异常的异常块中访问引发函数的局部变量?例如:
def myfunction():
v1 = get_a_value()
raise Exception()
try:
myfunction()
except:
# can I access v1 from here?
【问题讨论】:
如果您知道您的异常处理代码将需要它,将值传递给异常通常是更简洁的设计。但是,如果您正在编写调试器或类似的东西,您需要在不知道它们是哪些变量的情况下访问变量,您可以在异常发生的上下文中访问任意变量抛出:
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']
trace 函数的功能以及它所处理的traceback 对象的格式在inspect module documentation 中进行了描述。
【讨论】:
inspect.trace 是解释器堆栈的高级接口。不过,它在幕后使用sys.exc_info。 (实现是return getinnerframes(sys.exc_info()[2], context)。)虽然我不会说任何一种方式都必然不正确,但使用inspect 的功能可能是更好的形式,因为您不必担心实现细节,而且它会让你更清楚你在做什么。
可以在frame对象中查找局部变量,可以从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}
您必须包含适当数量的tb_nexts,具体取决于引发异常的堆栈深度。
【讨论】:
def myFunction()
v1 = get_a_value()
raise Exception(v1)
try:
myFunction()
except Exception, e:
v1 = e.args[0]
【讨论】:
raise Exception(locals()) 如果你想要所有的局部变量
是的,如果它是您自己的异常类型。像这样:
>>> 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 "<stdin>", line 1, in <module>
File "<stdin>", 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']
【讨论】:
对于不使用raise Exception(some_def_var) 以及不使用诸如“inspect”之类的库的“处理”异常很有用。
但是,我认为如果要“真正”处理异常,使用raise Exception(some_def_var) 之类的东西可能会更好。 See @capfredf answer.
class MyClass():
def __init__(self):
self.my_attr_I = ""
self.my_attr_II = ""
def my_def_I(self):
try:
self.my_def_II()
except Exception as e:
print(self.my_attr_I)
print(self.my_attr_II)
def my_def_II(self):
self.my_attr_I = "TO EXCEPT I"
self.my_attr_II = "TO except II"
# NOTE: We will treat it as a general exception! By Questor
zero_division = 1/0
【讨论】: