Python __del__ 在异常情况下未被调用

8
我正在尝试将一个编写不良的Python模块(我无法控制)包装成一个类。问题是,如果我不显式调用该模块的关闭函数,那么Python进程在退出时会挂起,因此我尝试使用一个带有del方法的类来包装该模块,但是在异常情况下del方法似乎不会被调用。
示例:
class Test(object):
    def __init__(self):
        # Initialize the problematic module here
        print "Initializing"

    def __del__(self):
        # Close the problematic module here
        print "Closing"

t = Test()
# This raises an exception
moo()

在这种情况下,Python不会调用del函数而会卡住。我需要找到一种方法,在对象超出范围时强制Python立即调用del函数(就像C++那样)。请注意,我无法控制有问题的模块(即无法修复导致此问题的错误),也无法控制使用包装类的人(无法强制他们使用“with”语句,因此也不能使用exit)。有没有什么好的解决方法?谢谢!

3
不要使用 __del__。Python不是C++或其他语言,也不是为析构函数而设计的。尽管我相信会有人找到合理的用例,但在Python 3.x中应该摒弃 del 方法。如果你必须使用 __del__,请参考 http://docs.python.org/reference/datamodel.html,了解其基本限制。 - harshil9968
2
用上下文管理器包装它? - jonrsharpe
就像我说的那样,我无法控制使用该类的人。我不能强迫他们使用“with”。 - Dan
@harshil9968 没有理由不调用 del。它的行为是确定性的。你只需要知道它的工作原理。但是,在这个问题的背景下,它不会按预期工作 :) - ivarec
Python中的__del__不起作用作为析构函数? - aschipfl
3个回答

5

如果你希望在异常情况下释放某些资源,请考虑使用 __enter__ + __exit__ 模式。

class Test(object):
    def __enter__(self):
        pass

    def __exit__(self):
        pass  # Release your resources here

with Test() as t:
    moo()

当执行进入“with”块时,会调用“t”的__enter__()方法,然后由于正常流或异常而离开该块,“t”的__exit__()方法将被调用。

请注意我的评论的最后一部分 - 我无法控制谁使用包装类或如何使用它,即我不能强制他们使用“with”。任何解决方案都必须仅在包装类代码内实现。 - Dan
好的,但是你可以控制使用该类的代码吗?你可以在客户端代码中使用__enter__ / __exit__。我只是为了说明这个想法而放置了Test类。还有其他实现进入/退出的方法,例如使用@contextlib.contextmanger。 - Dmitry T.
嗨,对于使用该类的代码,我无法进行任何控制。 - Dan
3
__exit__的签名比较长,不仅仅包括self - Azat Ibrakov

1

一种可能的解决方案是使用sys.excepthook,它允许您向全局异常处理程序引入自定义登录。您可以在那里添加一些代码来关闭模块中的剩余部分。


1
请查看以下详细信息:

class Test:
    def __init__(self):
        print('cons')
    
    def __del__(self):
        print('des')

如果我们将Test类的对象添加到某个全局字典中,并在功能完成后清除该字典,它将调用析构函数。
ctx = {}
def a():
    ctx['ao'] = Test()
    raise 1/0

a()

# cons
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "<stdin>", line 3, in a
# ZeroDivisionError: integer division or modulo by zero

如果我们释放ctx的旧内容并赋予新值,析构函数将被调用。
ctx  = {}
# des

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接