我一直在寻找在python中清理对象的方法。 我现在正在使用pypy。
我找到了一个网页和一个例子。
首先是一个基本的例子:
class FooType(object):
def __init__(self, id):
self.id = id
print self.id, 'born'
def __del__(self):
print self.id, 'died'
ft = FooType(1)
这应该打印:
1出生 1死了
但它只是打印 1出生
所以我的问题是:如何在PyPy中清理任何东西?
答案 0 :(得分:4)
应该在每个其他Python实现中执行此操作,包括CPython :通过显式管理代码中的生命周期,而不是依赖于自动内存管理和__del__
。
即使在CPython中,也有不止一种情况__del__
根本没有被称为 ,而且很多情况下它的调用时间比您预期的要晚得多(例如,任何时候任何对象都会陷入参考周期,这很容易发生。这意味着它基本上没用,除了可能调试生命周期问题(但有内存分析器!)和最后的手段,如果某些代码忽略明确清理。
通过明确清理,你可以回避所有这些问题。有一个方法可以进行清理,并让客户端代码在适当的时候调用它。上下文管理器可以使这更容易在面对异常时正确,并且更具可读性。它通常还允许比__del__
更早清理,甚至如果引用计数“立即”调用__del__
。例如,这个:
def parse_file(path):
f = open(path)
return parse(f.read()) # file stays open during parsing
比这更糟糕了。资源使用情况:
def parse_file(path):
with open(path) as f:
s = f.read()
# file is closed here
return parse(s)
我还认为这样的设计更简洁,因为它不会将资源包装器对象的生命周期与包装资源的生命周期混淆。有时,让该对象比资源更长,或者甚至让它拥有新资源的所有权是有意义的。
答案 1 :(得分:2)
在您的示例中,未调用__del__
,但这只是因为您编写的测试程序立即完成。 PyPy保证在对象不再可访问之后的某个时间调用__del__
,但只有在程序继续执行时才会调用ft = FooType(1)
。因此,如果您在无限循环中执行died
,它将在一段时间后打印__del__
。
正如其他答案所解释的那样,CPython并不能保证任何东西,但在简单的情况下(例如没有参考周期),它会立即可靠地调用{{1}}。不过,重点是你不应该严格依赖它。