如何确保通常(但错误地)期望在Python类上调用__del__函数?

时间:2018-07-25 07:39:49

标签: python python-3.x python-2.7

我了解Python类is not treated in the way that many people might expect__del__函数:作为析构函数。

我还理解,还有更多的“ pythonic”和可以说是更优雅的整理方式,尤其是使用with construct时。

但是,当编写可能不熟悉python方式的读者使用的代码时,当清理很重要时,是否有一种优雅的方法可以使__del__可靠地充当析构函数,而不会干扰python自然使用__del__吗?

__del__充当析构函数的期望似乎不是不合理,同时也很普遍。因此,我只是想知道是否有一种优雅的方法来使它按预期运行-忽略了关于pythonic的优缺点可以进行的许多辩论。

2 个答案:

答案 0 :(得分:1)

如果您了解所有这些内容,为什么不以Pythonic的方式来做呢?比较另一个需要清除的类:tempfile.TemporaryDirectory

with TemporaryDirectory() as tmp:
    # ...
# tmp is deleted

def foo():
    tmp = TemporaryDirectory()
foo()
# tmp is deleted

他们如何做到这一点?这是相关的位:

import weakref
class Foo():
    def __init__(self, name):
        self.name = name
        self._finalizer = weakref.finalize(self, self._cleanup, self.name)
        print("%s reporting for duty!" % name)

    @classmethod
    def _cleanup(cls, name):
        print("%s feels forgotten! Bye!" % name)

    def cleanup(self):
        if self._finalizer.detach():
            print("%s told to go away! Bye!" % self.name)

def foo():
    print("Calling Arnold")
    tmpfoo = Foo("Arnold")
    print("Finishing with Arnold")

foo()
# => Calling Arnold
# => Arnold reporting for duty
# => Finishing with Arnold
# => Arnold feels forgotten. Bye!

def bar():
    print("Calling Rocky")
    tmpbar = Foo("Rocky")
    tmpbar.cleanup()
    print("Finishing with Rocky")

bar()
# => Calling Rocky
# => Rocky reporting for duty!
# => Rocky told to go away! Bye!
# => Finishing with Rocky

weakref.finalize将在对象被垃圾收集时触发_cleanup,或者如果该对象仍然存在,则在程序结束时触发。我们可以保留终结器,以便我们可以明确杀死对象(使用detach)并将其标记为已死,以便不调用终结器(当我们要手动处理清理操作时)。

如果您想通过with支持上下文使用,则添加__enter____exit__方法很简单,只需在cleanup中调用__exit__(如上所述的“手动清理”。

答案 1 :(得分:-1)

这是我一直使用的一种模式,该模式使用atexit python模块来实现。

class Demo(object):
    def __init__(self, *args, **kwargs):
        import atexit
        atexit.register(self.__del__)

    def __del__(self):
        print("__del__ being called!")

t1 = Demo()
t2 = Demo()

quit()

当粘贴到python命令提示符中时,这是总输出:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> class Demo(object):
...     def __init__(self, *args, **kwargs):
...         import atexit
...         atexit.register(self.__del__)
...
...     def __del__(self):
...         print("__del__ being called!")
...
>>> t1 = Demo()
>>> t2 = Demo()
>>>
>>> quit()
__del__ being called!
__del__ being called!