python(CPython)で例外を投げると、例外を投げたフレームが例外をキャッチしたフレームに追加される。
このため、リファレンスカウントの動作が非自明になり、オブジェクトの寿命が意図せず延長される。
class Foo(Exception):
def __init__(self):
print 'construt'
def __del__(self):
print 'destruct'
def raiseError(self):
raise Exception()
def main ():
print 'enter main'
foo = Foo()
try:
foo.raiseError()
except:
print 'catch exception'
foo = None
print 'exit main'
try:
main()
finally:
print 'finish'
以上のコードの出力は以下のようになる。
enter main
construt
catch exception
exit main
destruct
finish
以上のように、main
内のfoo
オブジェクトを'exit main'の前に解放する事を意図したとしてもmain
のフレームが解放されるまでfoo
の寿命が延長される。
これは、例外を投げたraiseError
内のフレームが、main
内のフレームに保持され、raiseError
内のフレームはself = foo
を保持しているためだ。
例外フレームの解放はsys.exc_clear()
で行う。
似たようの事例としては、ループ内でtry-catchしている時に、ループ内で確保したオブジェクトの解放のタイミングが1ループ分ずれる等があり得る。
これは例外フレームが次のループでの例外スローによって解放されるからだ。