提问人:Mathieu 提问时间:8/29/2023 最后编辑:Mathieu 更新时间:9/6/2023 访问量:31
如果函数引发错误,则显式删除函数中的变量
Explicitly delete variables within a function if the function raised an error
问:
单元测试的一个特殊问题。我的许多测试函数具有以下结构:
def test_xxx():
try:
# do-something
variable1 = ...
variable2 = ...
except Exception as error:
raise error
finally:
try:
del variable1
except Exception:
pass
try:
del variable2
except Exception:
pass
这种结构显然不是很好。我可以用以下方式简化声明:finally
finally:
for variable in ("variable1", "variable2"):
if variable in locals():
del locals()[variable]
但它仍然不是那么好。相反,我想使用装饰器来处理 / / .del_variables
try
except
finally
尝试,不工作:
def del_variables(*variables):
def decorator(function):
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except Exception as error:
raise error
finally:
for variable in variables:
if variable in locals():
del locals()[variable]
return wrapper
return decorator
@del_variables("c")
def foo(a, b):
c = 3
return a + b + c
由于不引用执行 中的命名空间。如果我使用 ,我不知道我应该提供什么参数,因为就 Python 而言,该命名空间已经是 GC。任何知道我如何让该装饰器工作的想法,即我如何从命名空间中显式删除变量?locals()
function
vars()
function
注意:是的,这是一个奇怪的情况,我需要显式调用,因为我覆盖了某些对象的方法(存储在我要删除的变量中)来调用 c++ 函数来销毁附加的 c++ 对象和引用。不,在这种情况下,pytest 夹具不是一个好的解决方案;)del
__del__
答:
你真的应该考虑重构你的代码。一开始就依赖终结器不是一个好主意(例如,请参阅此问答)。有更好的机制可用于资源清理,例如上下文管理器和/或pytest固定装置。
话虽如此:
如果测试失败,pytest 将保留引发的异常。该异常包含所有堆栈帧。测试函数的堆栈帧包含对测试中创建的所有对象的引用。
使用当前解决方案时,只需删除测试函数中的引用。但是,对其他堆栈帧中的对象可能有更多引用。例如:
def func(some_obj):
raise Exception
def test_test():
obj = MyObj()
func(obj)
del obj
不会导致对象被垃圾回收,因为 Now 的堆栈帧仍然包含对该对象的引用。func
由于您无法通过调用堆栈合理地跟踪对对象的引用(它可能包含在其他对象等的字典中),因此我认为没有简单的方法可以像您请求的那样仅删除选定的对象。但是,假设对象没有全局或循环引用,则只需从后续帧中删除所有局部变量即可。哦,当然,我们只是在谈论 CPython。
这可以通过多种方式实现,但因为您需要一个装饰器:
import ctypes
import sys
def delete_locals(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
finally:
tb = sys.exc_info()[2]
if tb:
while tb.tb_next:
tb = tb.tb_next
tb.tb_frame.f_locals.clear()
ctypes.pythonapi.PyFrame_LocalsToFast(
ctypes.py_object(tb.tb_frame), ctypes.c_int(1)
) # reference: https://stackoverflow.com/a/34671307
return wrapper
请记住,pytest 现在也没有机会在其输出中告诉您局部变量的值。
评论
del
del
__del__
del
del