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 __== '__main__':
foo = Foo()
foo.open()
del foo
import gc
gc.collect()
_
ドキュメントでは、notが保証されていることを確認しました__del__()
メソッドは、インタープリターの終了時にまだ存在するオブジェクトに対して呼び出されます。
Foo
インスタンスに対して、バーが閉じていることをどのように保証できますか?del foo
_またはgc.collect()
...で閉じられますか?これらの詳細をより細かく制御したい場合(たとえば、オブジェクトが参照されていないときにバーを閉じる必要があります)、それを実装する通常の方法は何ですか?__del__
_が呼び出されると、___init__
_が既に呼び出されていることが保証されますか? ___init__
_が発生した場合はどうですか?リソースを閉じる方法は、コンテキストマネージャー、つまり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 __== '__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 __== '__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 __== '__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 __== '__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__
で作成され、self
として__init__
に渡されます。 __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
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()
を実行すると、実際には2つのことが行われます。最初に新しいオブジェクト__new__
が作成され、次に初期化されます__init__
。したがって、これらの両方のステップが実行される前にdel foo
を呼び出すことはできません。ただし、__init__
にエラーがある場合、オブジェクトは実際に__del__
で既に作成されているため、__new__
が呼び出されます。
編集:参照カウントがゼロに減少した場合に削除が発生すると修正されました。
おそらく、あなたは context manager ?を探していますか?
>>> 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__()
は、VMの実行中にオブジェクトへの参照の数が0に達したときに呼び出されます。これはGCが原因である可能性があります。__init__()
が例外を発生させた場合、オブジェクトは不完全であると見なされ、__del__()
は呼び出されません。