我了解Python类is not treated in the way that many people might expect的__del__
函数:作为析构函数。
我还理解,还有更多的“ pythonic”和可以说是更优雅的整理方式,尤其是使用with construct时。
但是,当编写可能不熟悉python方式的读者使用的代码时,当清理很重要时,是否有一种优雅的方法可以使__del__
可靠地充当析构函数,而不会干扰python自然使用__del__
吗?
对__del__
充当析构函数的期望似乎不是不合理,同时也很普遍。因此,我只是想知道是否有一种优雅的方法来使它按预期运行-忽略了关于pythonic的优缺点可以进行的许多辩论。
答案 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!