wim*_*wim 61 python constructor garbage-collection destructor reference-counting
我很好奇__del__python中的细节,何时以及为什么应该使用它以及它不应该用于什么.我已经学到了很难的方法,它不像人们对析构函数的天真期望,因为它不是__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()
Run Code Online (Sandbox Code Playgroud)
我在文档中看到,不保证__del__()在解释器退出时仍然存在的对象调用方法.
Foo解释器退出时存在的任何实例都关闭了吧?del foo还是gc.collect()......或者两者都没有?如果你想更好地控制那些细节(例如,当对象未被引用时应该关闭条形图)实现它的常用方法是什么?__del__被调用时能够保证所有的__init__已经叫什么名字?如果__init__举起怎么样?Joc*_*zel 70
关闭资源的方法是上下文管理器,即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
Run Code Online (Sandbox Code Playgroud)
输出:
opening the bar
<__main__.Foo object at 0x17079d0> open
closing the bar
Run Code Online (Sandbox Code Playgroud)
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"
Run Code Online (Sandbox Code Playgroud)
输出:
before
deling <__main__.Foo object at 0xc49690>
after
Run Code Online (Sandbox Code Playgroud)
这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"
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
3)让我们看看:
class Foo(object):
def __init__(self):
raise Exception
def __del__(self):
print "deling", self
if __name__ == '__main__':
f = Foo()
Run Code Online (Sandbox Code Playgroud)
得到:
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>
Run Code Online (Sandbox Code Playgroud)
创建对象__new__然后传递给__init__as self.在异常进入后__init__,该对象通常没有名称(即该f =部分未运行),因此它们的引用计数为0.这意味着该对象被正常删除并被__del__调用.
一般来说,为了确保无论发生什么事情,你都会使用
from exceptions import NameError
try:
f = open(x)
except ErrorType as e:
pass # handle the error
finally:
try:
f.close()
except NameError: pass
Run Code Online (Sandbox Code Playgroud)
finally无论块中是否存在错误,以及try块中发生的任何错误处理是否存在错误,都将运行except块.如果不处理引发的异常,则在finally块被激活后仍会引发异常.
确保文件关闭的一般方法是使用"上下文管理器".
http://docs.python.org/reference/datamodel.html#context-managers
with open(x) as f:
# do stuff
Run Code Online (Sandbox Code Playgroud)
这将自动关闭f.
对于你的问题#2,bar当引用计数达到零时立即关闭,del foo如果没有其他引用,则立即关闭.
对象不是由__init__它们创建的,它们是由它们创建的__new__.
http://docs.python.org/reference/datamodel.html#object.新
当你做foo = Foo()两件事实际上正在发生时,首先要创建一个新对象__new__,然后对它进行初始化__init__.因此,del foo在这两个步骤发生之前,你无法打电话.但是,如果存在错误__init__,__del__仍将调用,因为该对象实际上已在其中创建__new__.
编辑:如果引用计数减少到零,则在删除时进行更正.
也许您正在寻找上下文管理器?
>>> 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>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
107305 次 |
| 最近记录: |