如何确保像通常(但不正确)预期的那样在Python类上调用_del__)函数?
我理解Python类的如何确保像通常(但不正确)预期的那样在Python类上调用_del__)函数?,python,python-3.x,python-2.7,Python,Python 3.x,Python 2.7,我理解Python类的\uu del\uu函数:作为析构函数 我也知道有更多的“pythonic”和更优雅的方式来整理,特别是在使用 然而,当编写可能被不太熟悉python方式的用户使用的代码时,当清理非常重要时,有没有一种优雅的方法可以让\uu del_uu作为析构函数可靠地工作,而不影响python对\uu del_u的自然使用 期望\uu del\uu充当析构函数似乎并不不合理,同时也是很常见的。因此,我只是想知道是否有一种优雅的方式可以让它按照预期工作——忽略了关于它是多么pythoni
\uu del\uu
函数:作为析构函数
我也知道有更多的“pythonic”和更优雅的方式来整理,特别是在使用
然而,当编写可能被不太熟悉python方式的用户使用的代码时,当清理非常重要时,有没有一种优雅的方法可以让\uu del_uu
作为析构函数可靠地工作,而不影响python对\uu del_u
的自然使用
期望
\uu del\uu
充当析构函数似乎并不不合理,同时也是很常见的。因此,我只是想知道是否有一种优雅的方式可以让它按照预期工作——忽略了关于它是多么pythonic的优点的许多争论。这是我一直采用的一种模式,它通过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!
如果你了解所有这些,为什么不以蟒蛇的方式来做呢?比较另一个清理很重要的类:
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
将在垃圾收集对象时触发\u cleanup
,如果对象仍然存在,则在程序结束时触发。我们可以保留finalizer,这样我们就可以显式地终止对象(使用分离
),并将其标记为dead,这样就不会调用finalizer(当我们想要手动处理清理时)
如果您想用
和支持上下文使用,只需添加\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu方法即可(如上所述,手动清理).考虑警告用户,如果您必须在\uuu del\uuu
中进行清理,那么他们的程序实际上已损坏……您希望何时进行清理?范围是什么?记录您的代码,并展示如何将与
一起使用的示例。这并不难学,但我确实需要检查这样做对自然垃圾收集的影响,以及如果在退出之前对类进行垃圾收集会发生什么!呸!您可以在\uuu del\uuu
的末尾取消注册(self.\uu del\uuu)
,以避免垃圾收集+程序结束多次调用它。如果该模块是长时间运行的进程的一部分,该怎么办?您将\u cleanu
作为类方法的具体原因是什么?@Aran Fey:确实::“注意:重要的是确保func
、args
和kwargs
不直接或间接拥有对obj
的任何引用,否则将永远不会对obj
进行垃圾收集。”。特别是,func
不应该是obj
的绑定方法。“这意味着您没有访问终结器中实例的权限?那太没用了,不是吗?有没有办法将实例传递给终结器?@Aran Fey:这就不符合要点了。通过args/kwargs传递与终结器相关的任何信息,如name
此处。我认为如果它是无用的,它就不会被使用(很明显,在引用的TemporaryDirectory
类中就是这样)。@Aran Fey:“没有理由认为这是必要的。”编写Python文档的人肯定认为它是关键的。一方面,如果你有一个对对象的活动引用,它就不能被垃圾收集,所以weakref finalizer永远不会被触发;这是一个很好的理由,为什么它是必要的。尽管如此,在链接页面的底部仍然有一个关于finalize
vs\uuu del\uuu
的大讨论,您可能会发现,如果您确实需要从对象中获得一些在注册最终用户时不知道的信息,那么您可能会冒险走\uu del\uuu
和atexit
路线。