代码之家  ›  专栏  ›  技术社区  ›  QA Collective

如何确保对Python类调用'uuuu del_uu'函数,这是通常(但不正确)预期的?

  •  0
  • QA Collective  · 技术社区  · 6 年前

    我知道 __del__ Python类的函数 is not treated in the way that many people might expect :作为析构函数。

    我也明白有更多的“蟒蛇”和可以说更优雅的方法来整理,特别是使用 with construct .

    然而,当编写的代码可能被不太精通pythonic方法的读者使用时,当清理很重要时,有没有一种优雅的方法可以让我简单地 __德尔__ 可靠地作为析构函数工作,而不干扰python对 __德尔__ ?

    期望 __德尔__ 表现得像个毁灭者 不 像话 同时也是很普遍的。所以,我只是想知道是否有一种优雅的方法能让它按照预期工作——无视关于它是怎样的蟒蛇的优点的许多争论。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Amadan    6 年前

    如果你明白这些,为什么不用蟒蛇的方式呢?比较另一个清理很重要的类: 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 在里面 第二代 (“手动清理”如上所述)。

        2
  •  -1
  •   QA Collective    6 年前

    这是我一直采用的一种模式,它使用 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!