如何确保 __del__ 函数像通常(但不正确)预期的那样在 Python 类上调用? [英] How to ensure the __del__ function is called on a Python class as is commonly (but incorrectly) expected?
问题描述
我了解 Python 类的 __del__
函数 没有像许多人期望的那样处理:作为析构函数.
I understand that the __del__
function of a Python class is not treated in the way that many people might expect: as a destructor.
我也知道有更多pythonic"和可以说更优雅的整理方式,特别是使用 withconstruct.
I also understand that there are more 'pythonic' and arguably more elegant ways to tidy up, particularly with use of the with construct.
然而,当编写可能被不太熟悉 Pythonic 方式的观众使用的代码时,当清理很重要时,是否有一种优雅的方式可以让 __del__
可靠地作为析构函数工作,不干扰 python 对 __del__
的自然使用?
However, when writing code that may be used by an audience less versed in pythonic ways, when cleanup is important, is there an elegant way I can simply get __del__
to work as a destructor reliably, without interfering with python's natural use of __del__
?
期望 __del__
表现为析构函数似乎并不不合理,同时也很普遍.所以我只是想知道是否有一种优雅的方式让它按照预期工作 - 无视关于它是多么pythonic 的优点的许多争论.
The expectation that __del__
behave as a destructor doesn't seem unreasonable and at the same time is quite common. So I'm simply wondering if there is an elegant way to make it work as per that expectation - disregarding the many debates that can be had over the merits of how pythonic it is.
推荐答案
如果你理解了所有这些,为什么不以 Pythonic 的方式来做呢?比较另一个清理很重要的类:tempfile.TemporaryDirectory
.
If you understand all that, why not do it in the Pythonic way? Compare another class where cleanup is important: tempfile.TemporaryDirectory
.
with TemporaryDirectory() as tmp:
# ...
# tmp is deleted
def foo():
tmp = TemporaryDirectory()
foo()
# tmp is deleted
他们是怎么做到的?这是相关的部分:
How do they do this? Here's the relevant bit:
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
)并将其标记为死亡,这样终结器就不会被调用(当我们想要手动处理清理时).
weakref.finalize
will trigger _cleanup
when the object is garbage-collected, or at the end of the program if it's still around. We can keep the finaliser around so that we can explicitly kill the object (using detach
) and mark it as dead so the finaliser is not called (when we want to manually handle the cleanup).
如果你想支持with
的context用法,添加__enter__
和__exit__
方法很简单,只需要调用__exit__
中的清理(上面讨论的手动清理").
If you want to support the context usage with with
, it is trivial to add __enter__
and __exit__
methods, just invoke cleanup
in __exit__
("manual cleanup" as discussed above).
这篇关于如何确保 __del__ 函数像通常(但不正确)预期的那样在 Python 类上调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!