如何强制删除一个python对象?
我很好奇python中__del__
的细节,什么时候以及为什么它应该被使用,什么不应该被使用。 我已经学会了这样一个艰难的方式,它不是真正的天真地期望从析构函数中得到什么,因为它不是__new__
/ __init__
的对立面。
class Foo(object): def __init__(self): self.bar = None def open(self): if self.bar != 'open': print 'opening the bar' self.bar = 'open' def close(self): if self.bar != 'closed': print 'closing the bar' self.bar = 'close' def __del__(self): self.close() if __name__ == '__main__': foo = Foo() foo.open() del foo import gc gc.collect()
我在文档中看到, 不保证__del__()
方法在解释器退出时仍然存在的对象被调用。
- 如何保证解释器退出时存在的任何
Foo
实例都closures? - 在上面的代码片断,酒吧closures
del foo
或gc.collect()
…或两者都没有? 如果你想更好地控制这些细节(例如,当对象未被引用时,栏应该被closures),通常的方法是什么? - 当
__del__
被调用时,它保证__init__
已被调用? 那么如果__init__
提升呢?
closures资源的方式是上下文pipe理器,也就是with
声明:
class Foo(object): def __init__(self): self.bar = None def __enter__(self): if self.bar != 'open': print 'opening the bar' self.bar = 'open' return self # this is bound to the `as` part def close(self): if self.bar != 'closed': print 'closing the bar' self.bar = 'close' def __exit__(self, *err): self.close() if __name__ == '__main__': with Foo() as foo: print foo, foo.bar
输出:
opening the bar <__main__.Foo object at 0x17079d0> open closing the bar
2)Python的对象在引用计数为0时被删除。在你的例子中, del foo
删除了最后一个引用,所以立即调用__del__
。 GC没有任何内容。
class Foo(object): def __del__(self): print "deling", self if __name__ == '__main__': import gc gc.disable() # no gc f = Foo() print "before" del f # f gets deleted right away print "after"
输出:
before deling <__main__.Foo object at 0xc49690> after
gc
与删除你的和大多数其他对象无关。 由于自引用或循环引用,在简单引用计数不起作用的时候,可以清理它们:
class Foo(object): def __init__(self, other=None): # make a circular reference self.link = other if other is not None: other.link = self def __del__(self): print "deling", self if __name__ == '__main__': import gc gc.disable() f = Foo(Foo()) print "before" del f # nothing gets deleted here print "after" gc.collect() print gc.garbage # The GC knows the two Foos are garbage, but won't delete # them because they have a __del__ method print "after gc" # break up the cycle and delete the reference from gc.garbage del gc.garbage[0].link, gc.garbage[:] print "done"
输出:
before after [<__main__.Foo object at 0x22ed8d0>, <__main__.Foo object at 0x22ed950>] after gc deling <__main__.Foo object at 0x22ed950> deling <__main__.Foo object at 0x22ed8d0> done
3)让我们看看:
class Foo(object): def __init__(self): raise Exception def __del__(self): print "deling", self if __name__ == '__main__': f = Foo()
得到:
Traceback (most recent call last): File "asd.py", line 10, in <module> f = Foo() File "asd.py", line 4, in __init__ raise Exception Exception deling <__main__.Foo object at 0xa3a910>
对象是用__new__
创build的,然后以self
传递给__init__
。 在__init__
发生exception之后,对象通常没有名称(即f =
part不运行),所以它们的引用计数为0.这意味着对象被正常删除,并调用__del__
。
一般来说,为了确保不pipe发生什么事情,你使用
from exceptions import NameError try: f = open(x) except ErrorType as e: pass # handle the error finally: try: f.close() except NameError: pass
finally
块将被运行,无论在try
块中是否有错误,以及在except
块except
任何error handling中是否有错误。 如果你没有处理exception,那么在finally
块被执行之后,它仍然会被提升。
确保文件closures的一般方法是使用“上下文pipe理器”。
http://docs.python.org/reference/datamodel.html#context-managers
with open(x) as f: # do stuff
这会自动closuresf
。
对于你的问题#2,当引用计数达到零时, bar
会立即closures,所以如果没有其他引用, del foo
。
对象不是由__init__
创build的,它们是由__new__
创build的。
http://docs.python.org/reference/datamodel.html#object。; 新
当你做foo = Foo()
两件事实际上正在发生,首先是一个新的对象被创build, __new__
,然后它被初始化, __init__
。 所以在这两个步骤发生之前,你都不可能打电话给del foo
。 但是,如果__init__
有错误, __init__
__del__
仍将被调用,因为该对象实际上已经在__new__
创build。
编辑:如果引用计数减less到零,则发生删除。
也许你正在寻找一个上下文pipe理器 ?
>>> class Foo(object): ... def __init__(self): ... self.bar = None ... def __enter__(self): ... if self.bar != 'open': ... print 'opening the bar' ... self.bar = 'open' ... def __exit__(self, type_, value, traceback): ... if self.bar != 'closed': ... print 'closing the bar', type_, value, traceback ... self.bar = 'close' ... >>> >>> with Foo() as f: ... # oh no something crashes the program ... sys.exit(0) ... opening the bar closing the bar <type 'exceptions.SystemExit'> 0 <traceback object at 0xb7720cfc>
- 添加一个closures所有酒吧的退出处理程序 。
- 当虚拟机仍在运行时,当对象的引用数量达到0时,
__del__()
被调用。 这可能是由GC引起的。 - 如果
__init__()
引发一个exception,那么该对象被认为是不完整的,__del__()
将不会被调用。