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.')

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