atexit — Обработчики выхода


Модуль atexit определяет функции для регистрации и снятия с регистрации функций очистки. Зарегистрированные таким образом функции автоматически выполняются при обычном завершении работы интерпретатора. Модуль atexit запускает эти функции в порядке, обратном тому, в котором они были зарегистрированы; если вы зарегистрируете A, B и C, то при завершении работы интерпретатора они будут выполняться в порядке C, B, A.

Примечание: Функции, зарегистрированные в этом модуле, не вызываются, когда программа завершается по сигналу, не обрабатываемому Python, когда обнаруживается фатальная внутренняя ошибка Python или когда вызывается os._exit().

Примечание: Эффект регистрации или снятия с регистрации функций изнутри функции очистки не определен.

Изменено в версии 3.7: При использовании с субинтерпретаторами C-API зарегистрированные функции являются локальными для интерпретатора, в котором они были зарегистрированы.

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

Зарегистрируйте func как функцию, которая будет выполняться при завершении. Любые необязательные аргументы, которые должны быть переданы в func, должны быть переданы в качестве аргументов в register(). Одну и ту же функцию и аргументы можно зарегистрировать несколько раз.

При обычном завершении программы (например, при вызове sys.exit() или завершении выполнения главного модуля) все зарегистрированные функции вызываются в порядке «последний вошел, первый вышел». Предполагается, что модули нижнего уровня обычно импортируются раньше модулей верхнего уровня и поэтому должны быть очищены позже.

Если во время выполнения обработчиков выхода возникает исключение, печатается обратная трассировка (если только не возникло SystemExit) и сохраняется информация об исключении. После того как все обработчики выхода успеют выполниться, последнее поднятое исключение будет поднято повторно.

Эта функция возвращает func, что позволяет использовать ее в качестве декоратора.

Предупреждение

Запуск новых потоков или вызов os.fork() из зарегистрированной функции может привести к состоянию гонки между основным потоком выполнения Python, освобождающим состояние потока, и внутренними threading подпрограммами или новым процессом, пытающимся использовать это состояние. Это может привести к сбоям, а не к чистому завершению работы.

Изменено в версии 3.12: Попытки запустить новый поток или os.fork() новый процесс в зарегистрированной функции теперь приводят к RuntimeError.

atexit.unregister(func)

Удалить func из списка функций, запускаемых при завершении работы интерпретатора. unregister() молча ничего не делает, если func не была зарегистрирована ранее. Если func была зарегистрирована более одного раза, будет удалено каждое вхождение этой функции в стеке вызовов atexit. Сравнение равенств (==) используется внутренне при снятии с регистрации, поэтому ссылки на функции не обязательно должны иметь совпадающие идентификаторы.

См.также

Модуль readline

Полезный пример использования atexit для чтения и записи файлов истории readline.

atexit Пример

Следующий простой пример демонстрирует, как модуль может инициализировать счетчик из файла при его импорте и автоматически сохранять обновленное значение счетчика при завершении программы, не требуя от приложения явного вызова этого модуля при завершении работы.

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

Использование в качестве decorator:

import atexit

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

Это работает только с функциями, которые можно вызывать без аргументов.