"atexit" --- Exit handlers
**************************

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

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

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

**Note:** The effect of registering or unregistering functions from
within a cleanup function is undefined.

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

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

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

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

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

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

   警告:

     Starting new threads or calling "os.fork()" from a registered
     function can lead to race condition between the main Python
     runtime thread freeing thread states while internal "threading"
     routines or the new process try to use that state. This can lead
     to crashes rather than clean shutdown.

   バージョン 3.12 で変更: Attempts to start a new thread or
   "os.fork()" a new process in a registered function now leads to
   "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.')

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