Python - プログラム終了時に自動的に関数を呼び出す

atexit.register() メソッドを使用して関数を登録すると、プログラムが終了する際にその関数が呼び出されます。リソースのクリーンアップや重要な終了処理を行うのに有効です。

プログラム終了時に呼び出される関数の登録方法

import atexit

atexit.register(<プログラム終了時に実行する関数>)
atexit.register(<プログラム終了時に実行する関数>, <関数に渡す引数>)
atexit.register(<プログラム終了時に実行する関数>, <関数に渡す引数1>, <関数に渡す引数2>,...)

サンプルコード1

次のサンプルコードは atexit.register() メソッドを使用して2つの関数を登録しています。最後に登録された関数から順に呼び出されるため、メッセージは「2.プログラム終了」「1.プログラム終了」の順で表示されます。
import atexit


# プログラム終了時に呼びたい関数
def cleanup1():
    print('1.プログラム終了')

# プログラム終了時に呼びたい関数
def cleanup2():
    print('2.プログラム終了')


# プログラム終了時に呼び出される関数を登録
atexit.register(cleanup1)
atexit.register(cleanup2)

サンプルコード2

次のサンプルコードは、関数の登録時に2つの引数を渡しています。関数は 2つの引数を結合して表示するため、「2.プログラム終了」「1.プログラム終了」の順で表示されます。
import atexit


# プログラム終了時に呼びたい関数
def cleanup(message1, message2):
    print(message1 + message2)


# 2つの引数とともに、プログラム終了時に呼び出される関数を登録
atexit.register(cleanup, '1.', 'プログラム終了')
atexit.register(cleanup, '2.', 'プログラム終了')

デコレータを使用して関数を登録する

関数を登録するためのデコレータも用意されています。プログラム終了時に呼び出したい関数にデコレータ @atexit.register を指定します。
import atexit

@atexit.register
def <関数名>():
    <終了時に実行したい処理>

サンプルコード

次のサンプルコードは、デコレータを使用してプログラム終了時に呼び出す関数を登録しています。最後に定義された関数から順に呼び出されるため、「2.プログラム終了」「1.プログラム終了」の順で表示されます。
import atexit


@atexit.register
def cleanup1():
    print('1.プログラム終了')

@atexit.register
def cleanup2():
    print('2.プログラム終了')

登録した関数の削除

atexit.unregister() メソッドの引数に、削除したい関数を渡します。
import atexit

atexit.unregister(<削除する関数>)

サンプルコード

次のサンプルコードでは、atexit.unregister() メソッドを使用して、atexit.register() で登録した関数を削除しています。登録が2回に対し、削除は1回行われています。しかし、同名の関数は全て削除されるため、結果として何も表示されません。
import atexit


def cleanup(message1, message2):
    print(message1 + message2)


# 2つの引数とともに、プログラム終了時に呼び出される関数を登録
atexit.register(cleanup, '1.', 'プログラム終了')
atexit.register(cleanup, '2.', 'プログラム終了')


# 登録した関数を削除
atexit.unregister(cleanup)

登録した関数内で例外が発生した場合

リソースのクリーンアップや重要な終了処理を確実に行うため、atexit.register() で登録された関数は、例外が発生しても全て呼び出されます。

サンプルコード

次のサンプルコードでは、cleanup2() -> cleanup1() の順に実行されますが、cleanup2() 内で例外を発生させています。 例外が発生しても全ての関数が呼び出されるため、'プログラム終了' のメッセージも表示されます。
import atexit

@atexit.register
def cleanup1():
    print('プログラム終了')

@atexit.register
def cleanup2():
    # 例外を発生させる
    raise ValueError("例外発生")

サンプルプログラムの実行結果

D:\test>python sample-cleanup-raise.py
Exception ignored in atexit callback: <function cleanup3 at 0x0000021FE8BFD080>
Traceback (most recent call last):
  File "D:\test\sample-cleanup-raise.py", line 17, in cleanup3
    raise ValueError("2.error")
ValueError: 2.error
Exception ignored in atexit callback: <function cleanup2 at 0x0000021FE8BF0EA0>
Traceback (most recent call last):
  File "D:\test\sample-cleanup-raise.py", line 12, in cleanup2
    raise ValueError("1.error")
ValueError: 1.error
プログラム終了
サンプルプログラムの実行結果
サンプルプログラムの実行結果

登録した関数が呼ばれないケース

通常、登録された関数は sys.exit()、exit()、quit() が呼び出されたとき、あるいは、メインモジュールの実行が完了したときに呼ばれます。しかし、次のようなケースでは呼ばれません。

参考資料

検証環境