Python 在处理来自sys.exc_info()的回溯对象时应适当小心并确保安全
我知道文档中说在处理回溯对象时要小心,但我仍然不确定某些情况有多安全或不安全。此外,文档上写着“警告:不要这样做!”,紧接着是“注意:实际上,没问题”,这让我更加困惑 无论如何,docs和“”(Alex Martelli的答案)似乎暗示了它唯一的局部变量,这些变量引用了分配给它们的回溯值,从而导致了问题 这给我留下了几个问题:Python 在处理来自sys.exc_info()的回溯对象时应适当小心并确保安全,python,exception,error-handling,circular-reference,Python,Exception,Error Handling,Circular Reference,我知道文档中说在处理回溯对象时要小心,但我仍然不确定某些情况有多安全或不安全。此外,文档上写着“警告:不要这样做!”,紧接着是“注意:实际上,没问题”,这让我更加困惑 无论如何,docs和“”(Alex Martelli的答案)似乎暗示了它唯一的局部变量,这些变量引用了分配给它们的回溯值,从而导致了问题 这给我留下了几个问题: 在这种情况下,“局部变量”到底意味着什么?我正在努力寻找术语,但是:这是指只在函数中创建变量,还是也指由函数参数创建的变量?范围中的其他变量如何,例如全局变量或self
def DoWebRequest():
thread, error_queue = CreateThread(ErrorRaisingFunc)
thread.start()
thread.join()
if not error_queue.empty():
# Purposefully not calling error_queue.get() for illustrative purposes
print 'error!'
def CreateThread(func):
error_queue = Queue.Queue()
def Handled():
try:
func()
except Exception:
error_queue.put(sys.exc_info())
thread = threading.Thread(target=Handled)
return thread, error_queue
Handled()
关闭是否会导致引用错误队列
引发任何异常并导致循环引用,因为错误队列
也包含回溯?从错误队列
移除回溯(即调用.get()
)是否足以消除循环引用
示例2:exc_info范围内的长寿命对象,或返回exc_info
long_lived_cache = {}
def Alpha(key):
expensive_object = long_lived_cache.get(key)
if not expensive_object:
expensive_object = ComputeExpensiveObject()
long_lived_cache[key] = expensive_object
exc_info = AlphaSub(expensive_object)
if exc_info:
print 'error!', exc_info
def AlphaSub(expensive_object):
try:
ErrorRaisingFunc(expensive_object)
return None
except Exception:
return sys.exc_info()
AlphaSub()
引发的异常是否引用了昂贵的\u对象
,并且由于昂贵的\u对象
被缓存,回溯永远不会消失?如果是这样,如何打破这样的循环
或者,exc_info
包含Alpha
堆栈帧,Alpha
堆栈帧包含对exc_info
的引用,从而产生循环引用。如果是这样,如何打破这种循环
在这种情况下,“局部变量”到底意味着什么?我正在努力寻找术语,但是:这是指仅在函数中创建的变量,还是也指由函数参数创建的变量?范围内的其他变量,例如全局变量还是自变量
“局部变量”是在函数内创建的所有名称绑定。这包括任何函数参数和分配的任何变量。例如,在以下情况中:
def func(fruwappah, qitzy=None):
if fruwappah:
fruit_cake = 'plain'
else:
fruit_cake = qitzy
frosting = 'orange'
变量fruwappah
、qitzy
、fruit_-cake
和frosting
都是本地变量。哦,既然self
在函数头中(在我的示例中不是这样),它也是本地变量
闭包是如何影响回溯的潜在循环引用的?一般的想法是:闭包可以引用它的封闭函数所能引用的所有东西,因此引用闭包的回溯最终可能会引用很多东西。我正在努力想出一个更具体的例子,但是一些组合:内部函数,返回sys.exc_info()的代码,其作用域中某处存在昂贵的短期对象
正如您链接到的答案所述:回溯引用在异常发生时处于活动状态的每个函数(及其变量)。换句话说,是否涉及闭包是不相关的——分配给闭包(非局部)或全局变量将创建循环引用
有两种基本方法可以解决这一问题:
del traceback\u object
说到这里,我还需要在我自己的代码中使用traceback对象——异常及其各种属性到目前为止已经足够了。Ethan,如果您想捕获在另一个线程中引发的异常,情况如何?我遇到的矛盾是,线程必须存储异常(因此,回溯有一个指向自身存储位置的引用),这取决于线程调用方(或除ThreadWithException之外的任何人)。实际上,我想我找到了一个方法。你应该添加第三点:
del
任何包含回溯传递引用的对象。例如,try:func();除了:obj.exc=sys.exc_info();del obj
。从检查gc.get_objects()
可以看出,有问题的对象的refcount下降到0(obj
,exc_info),并打破循环,我应该澄清:通过检查回溯帧,不再有对obj
的引用,因此obj
引用回溯,但回溯不引用obj
技巧是从回溯对象中提取所需的任何信息,然后去掉回溯对象项目。顺便说一句,哟