"atexit" --- 終了ハンドラー
***************************

======================================================================

"atexit" モジュールは、クリーンアップ関数の登録およびその解除を行う関
数を定義します。登録された関数はインタプリタの通常終了時に自動的に実行
されます。"atexit" はそれら関数を登録した順と *逆に* 実行します; "A"、
"B"、"C" の順に登録した場合、インタプリタ終了時に "C"、"B"、"A" の順に
実行されます。

**注意:** このモジュールを使用して登録された関数は、プログラムが
Python が扱わないシグナルによって kill された場合、Python 内部で致命的
なエラーが検出された場合、あるいは "os._exit()" が呼び出された場合は実
行されません。

**注意:** クリーンアップ関数内からの関数の登録・登録解除効果は定義され
ていません。

バージョン 3.7 で変更: C-API のサブインタープリタで使われているとき、
登録された関数は登録先のインタープリタのローカルな関数になります。

atexit.register(func, *args, **kwargs)

   *func* を終了時に実行する関数として登録します。*func* に渡す引数は
   "register()" の引数として指定しなければなりません。同じ関数を同じ引
   数で複数回登録できます。

   通常のプログラムの終了時、例えば "sys.exit()" が呼び出されるとき、
   あるいは、メインモジュールの実行が完了したときに、登録された全ての
   関数を、最後に登録されたものから順に呼び出します。通常、より低レベ
   ルのモジュールはより高レベルのモジュールより前に import されるので
   、後で後始末が行われるという仮定に基づいています。

   終了ハンドラの実行中に例外が発生すると、("SystemExit" 以外の場合は)
   トレースバックを表示して、例外の情報を保存します。全ての終了ハンド
   ラに動作するチャンスを与えた後に、最後に送出された例外を再送出しま
   す。

   この関数は *func* を返し、これをデコレータとして利用できます。

   警告:

     登録された関数から新しいスレッドを開始したり、 "os.fork()" を呼び
     出したりすると、メインの Python ランタイムスレッドがスレッド状態
     を開放する一方で、内部の "threading" ルーチンや新しいプロセスがそ
     のスレッド状態を使用しようと試みる競合が発生します。これはクリー
     ンなシャットダウンではなく、クラッシュにつながる恐れがあります。

   バージョン 3.12 で変更: 登録された関数から新しいスレッドの開始また
   は新しいプロセスの "os.fork()" が試みられた場合は、 "RuntimeError"
   が発生するようになりました。

atexit.unregister(func)

   関数 *func* をインタプリタ終了時に実行する関数のリストから削除しま
   す。*func* が登録されていなければ、"unregister()" は何もしません。
   *func* が2回以上登録されている場合は "atexit" のコールスタックにお
   ける *func* のすべての出現が削除されます。削除の際の比較には等価比
   較 ("==") が使われます。したがって削除したいものと同一の関数を
   *func* に指定する必要はありません。

参考:

  "readline" モジュール
     "readline" ヒストリファイルを読み書きするための "atexit" の有用な
     例です。


"atexit" の例
=============

次の簡単な例では、あるモジュールを import した時にカウンタを初期化して
おき、プログラムが終了するときにアプリケーションがこのモジュールを明示
的に呼び出さなくてもカウンタが更新されるようにする方法を示しています。

   try:
       with open('counterfile') as infile:
           _count = int(infile.read())
   except FileNotFoundError:
       _count = 0

   def incrcounter(n):
       global _count
       _count = _count + n

   def savecounter():
       with open('counterfile', 'w') as outfile:
           outfile.write('%d' % _count)

   import atexit

   atexit.register(savecounter)

"register()" に指定した位置引数とキーワード引数は登録した関数を呼び出
す際に渡されます:

   def goodbye(name, adjective):
       print('Goodbye %s, it was %s to meet you.' % (name, adjective))

   import atexit

   atexit.register(goodbye, 'Donny', 'nice')
   # or:
   atexit.register(goodbye, adjective='nice', name='Donny')

*デコレータ* として利用する例:

   import atexit

   @atexit.register
   def goodbye():
       print('You are now leaving the Python sector.')

デコレータとして利用できるのは、その関数が引数なしで呼び出された場合に
限られます。
