# `atexit` --- 退出處理函式

The `atexit` module defines functions to register and unregister cleanup functions. Functions thus registered are automatically executed upon normal interpreter termination. `atexit` runs these functions in the reverse order in which they were registered; if you register `A`, `B`, and `C`, at interpreter termination time they will be run in the order `C`, `B`, `A`.

注意：當程式被一個不是來自 Python 的訊號終止、偵測到有 Python 嚴重內部錯誤時或者 `os._exit()` 被呼叫時，透過此模組註冊的函式就不會被呼叫。

注意：在清理函式中註冊或註銷函式的作用並未定義。

在 3.7 版的變更: 當與 C-API 子直譯器 (subinterpreter) 一起使用時，已註冊函式對於它們所註冊的直譯器來說是區域的 (local)。

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

  將 func 註冊為要在終止時執行的函式。任何要傳遞給 func 的可選引數都必須作為引數傳遞給 `register()`。可以多次註冊相同的函式和引數。

  在程式正常終止時（例如呼叫 `sys.exit()` 或主要模組執行完成），所有已註冊函式都會依照後進先出的順序呼叫。這邊做的假設是較低階的模組通常會在較高階模組之前被引入，因此較低階模組必須在比較後面才被清理。

  如果在執行退出處理函式期間引發例外，則會列印回溯 (traceback)（除非引發 `SystemExit`）並儲存例外資訊。在所有退出處理函式都有嘗試運作過後，將重新引發最後一個引發的例外。

  該函式回傳 func，這使得可以將其作為裝飾器使用。

  警告

  啟動新執行緒或從已註冊函式呼叫 `os.fork()` 可能會導致 Python 主要 runtime 執行緒釋放執行緒狀態，而內部 `threading` 例程或新行程嘗試使用該狀態所形成的競態條件 (race condition)。這可能會導致崩潰 (crash) 而不是完整關閉中止。

  在 3.12 版的變更: 嘗試在已註冊函式中啟動新執行緒或 `os.fork()` 新行程現在會導致 `RuntimeError`。

atexit.unregister(func)

  Remove func from the list of functions to be run at interpreter shutdown. `unregister()` silently does nothing if func was not previously registered. If func has been registered more than once, every occurrence of that function in the `atexit` call stack will be removed. Equality comparisons (`==`) are used internally during unregistration, so function references do not need to have matching identities.

也參考

`readline` 模組

  Useful example of `atexit` to read and write `readline` history files.

## `atexit` Example

以下的簡單範例示範了模組如何在被引入時以檔案來初始化計數器，並在程式終止時自動儲存計數器的更新值，而不需要仰賴應用程式在終止時明確呼叫該模組。

    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')
    # 或是：
    atexit.register(goodbye, adjective='nice', name='Donny')

作為裝飾器使用：

    import atexit

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

這只適用於可以不帶引數呼叫的函式。