Как принудительно удалить объект python?
мне любопытно узнать подробности __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()
Я видел в документации, что это не гарантированный __del__()
методы вызываются для объектов, которые все еще существуют при выходе интерпретатора.
- как можно гарантировать, что для любого
Foo
экземпляры, существующие при выходе интерпретатора, бар закрыт? - в приведенном выше фрагменте кода бар закрывается на
del foo
илиgc.collect()
... или нет? если вы хотите более точный контроль этих деталей (например, бар должен быть закрыт, когда объект не связан), каков обычный способ реализовать это? - , когда
__del__
называется это гарантировано, что__init__
уже звонил? а что если__init__
подняли?
4 ответа:
способ закрыть ресурсы-это контекстные менеджеры, ака
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__
вызывается мгновенно. ГК в этом не участвует.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
The
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__
затем перешел к__init__
какself
. После исключения в__init__
, объект обычно не имеет имени (Т. е.f =
часть не запускается), поэтому их количество ref равно 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
finally
блоки будут запущены независимо от того, есть ли ошибка вtry
блок, и есть ли ошибка в любой обработке ошибок, которая имеет место вexcept
блоки. Если вы не обрабатываете возникшее исключение, оно все равно будет возникать послеfinally
блок оформить.общий способ убедиться, что файл закрыт, является использование "контекста менеджер."
http://docs.python.org/reference/datamodel.html#context-managers
with open(x) as f: # do stuff
это автоматически закрыть
f
.для вашего вопроса #2,
bar
закрывается сразу же, когда счетчик ссылок достигает нуля, так чтоdel foo
если нет других ссылок.объекты не создаются
__init__
, они создаются__new__
.http://docs.python.org/reference/datamodel.html#object.new
когда вы
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>
- добавить обработчик выхода это закрывает все бары.
__del__()
вызывается, когда число ссылок на объект достигает 0, пока виртуальная машина все еще работает. Это может быть вызвано GC.- если
__init__()
вызывает исключение, то объект считается неполным и__del__()
не вызывается.