如何在Python程序的其他部分调用sys.exc_clear()?
我有一个类(如果你感兴趣,可以看看之前的问题),这个类用来跟踪一些事情,包括错误。这个类在多种情况下被调用,其中之一是在发生异常的时候。尽管我的类在正常情况下会调用 sys.exc_clear()
,但下次调用这个类时(即使没有错误,比如我只是想在类的某个函数里放一些统计信息),sys.exc_info()
返回的元组仍然包含之前的非 None
对象。
我可以在类执行时调用 sys.exc_clear()
,这时 sys.exc_info()
返回的就是一堆 None
,但是一旦执行返回到主程序,这个情况就不再成立了。我查阅文档后了解到,这可能是因为执行栈回到了另一个框架。这种情况在之前的问题中也有提到。
所以,我唯一的选择似乎是在主程序的每个 except
后面加上 sys.exc_clear()
。我在几个地方试过,确实有效。我可以这样做,但感觉很繁琐,也不太美观。有没有其他的方法呢?
补充:
想象一下主程序是:
import tracking
def Important_Function():
try:
something that fails
except:
myTrack.track(level='warning', technical='Failure in Important_Function' ...)
return
def Other_Function():
myTrack.track(level='info', technical='Total=0' ...)
return
myTrack = tracking.Tracking()
myTrack.track(level='debug', parties=['operator'], technical='Started the program.')
Important_Function()
Other_Function()
然后跟踪代码是:
import sys
import inspect
import traceback
... lots of initialization stuff
def track(self, level='info', technical=None, parties=None, clear=True ...):
# What are our errors?
errors = {}
errortype, errorvalue, errortraceback = sys.exc_info()
errortype, errorvalue = sys.exc_info()[:2]
errors['type'] = None
errors['class'] = errortype
errors['value'] = errorvalue
errors['arguments'] = None
errors['traceback'] = None
try:
errors['type'] = str(errortype.__name__)
try:
errors['arguments'] = str(errorvalue.__dict__['args'])
except KeyError:
pass
errors['traceback'] = traceback.format_tb(errortraceback, maxTBlevel)
except:
pass
if clear == True:
sys.exc_clear()
我知道没有多线程。如果我在调用 sys.exc_clear()
之后立刻打印 sys.exc_info()
,一切都会被清空。但是一旦我从 track
函数返回,然后再进入,即使没有错误,sys.exc_info()
又会返回之前的旧错误的元组。
2 个回答
我觉得这个错误是因为你不正确地使用了 sys.exc_clear()
和异常处理。真正的问题在于,你在处理完另一个异常后才调用它。这样清除的其实是那个异常,而不是你记录的那个。
解决这个问题的方法是,创建一个专门用来跟踪异常的方法,并且只在 except
语句块中调用它。这样一来,处理的异常总是正确的。
我在上面的代码中看到的一些问题:
- 你在处理完另一个异常后才调用
exc.clear_exc()
,这样清除的不是你想要的那个异常。 - 你想用
exc.clear_exc()
来清除别人的异常,这样做是错误的,可能会导致程序出错(比如,如果在调用了修复版的track
后又直接raise
,程序会失败)。处理异常的人通常需要用到那些值,像这样清除它们是没有好处的。 - 你认为如果没有错误,
sys.exc_info()
就不会被设置,只要你每次都清除它。这是不对的——在完全不相关的track
调用中,可能会有之前异常的数据。不要依赖这个。
所有这些问题都可以通过使用不同的方法来解决,并且永远不要使用 sys.clear_exc()
。
哦,还有一点,如果那些没有指定异常的 except:
语句不是例子,建议只处理你知道的异常,而不是像这样处理所有异常。
请注意,最后的异常信息是针对每个线程的。以下是来自sys.exc_info
的摘录:
这个函数会返回一个包含三个值的元组,这些值提供了关于当前正在处理的异常的信息。返回的信息是特定于当前线程和当前调用栈的。
所以,在一个线程中运行sys.exc_clear
不会影响其他线程。
更新:
引用文档中的内容:
警告
在处理异常的函数中将 traceback 的返回值赋给一个局部变量,会导致循环引用。这会阻止任何被该局部变量或 traceback 引用的内容被垃圾回收。由于大多数函数不需要访问 traceback,最好的解决办法是使用类似于 exctype, value = sys.exc_info()[:2] 的方式,只提取异常类型和异常值。如果确实需要 traceback,确保在使用后删除它(最好用 try ... finally 语句来完成),或者在一个不处理异常的函数中调用 exc_info()。
你确实将 traceback 赋值给了一个局部变量,这就是我在你的问题下评论建议你去掉“有问题”的那一行的原因。