Как работают коды выхода в Python 3 и способы завершения программы

Раздел: Ошибки -> Обработка ошибок в Python

Код выхода Python 3: exit и sys.exit()

Основной способ завершить программу с определённым кодом возврата в Python 3 - использовать функцию sys.exit([code]). Она выбрасывает исключение SystemExit, которое может быть перехвачено, но если этого не произошло, интерпретатор завершает работу, передавая операционной системе указанный код. Традиционно код 0 означает успешное завершение, любой ненулевой код - ошибку.


import sys

def main():
    try:
        # здесь основной код
        print("Программа работает")
        sys.exit(0)  # успешное завершение
    except SystemExit as e:
        print(f"Перехвачен SystemExit с кодом {e.code}")
        # по желанию можно снова выбросить или проигнорировать
        raise  # продолжить завершение

if __name__ == "__main__":
    main()

Python 3 exit (код выхода python 3 exit)

Программа работает
Перехвачен SystemExit с кодом 0

Если код не указан, sys.exit() завершает программу с кодом 0. Перехватывать SystemExit стоит только в редких случаях, например, для очистки ресурсов перед завершением. После перехвата можно повторно вызвать sys.exit() или просто выйти.

Как немедленно завершить процесс без вызова обработчиков и очистки?

Используйте os._exit(n). Эта функция завершает процесс сразу, минуя блоки finally, менеджеры контекста и прочие деструкторы. Она полезна в дочерних процессах после fork(), а также когда критично не выполнять лишний код.


import os
import sys

try:
    print("Начало работы")
    os._exit(1)  # завершение без исключения
except:
    # Этот блок не выполнится
    print("Исключение не произошло")
finally:
    # Этот блок тоже не выполнится
    print("finally не вызывается")
Начало работы

Типичная ошибка - использование os._exit() в обычных программах, где ожидается корректная очистка. Это может привести к потерянным данным или некорректному состоянию файлов. Кроме того, os._exit() не вызывает исключение, поэтому его перехват невозможен. Рекомендуется применять только в ситуациях, где мгновенное завершение необходимо.

Как завершить программу, не вызывая явно функцию exit?

Можно непосредственно возбудить исключение SystemExit. Это эквивалентно вызову sys.exit().


import sys

raise SystemExit(2)
# код после raise не выполнится
(программа завершается с кодом 2)

Такой подход иногда используется в однострочных скриптах или когда нужно завершить выполнение внутри обработчика.

Как указать успешное или ошибочное завершение с общепринятыми кодами?

Следуйте соглашениям: 0 - успех, 1 - общая ошибка, 2 - неправильное использование (например, неверные аргументы командной строки), 3 и выше - специфические для программы коды.


import sys

if len(sys.argv) != 2:
    print("Использование: script.py <имя>", file=sys.stderr)
    sys.exit(2)
try:
    with open(sys.argv[1]) as f:
        data = f.read()
except FileNotFoundError:
    print("Файл не найден", file=sys.stderr)
    sys.exit(1)
print(f"Файл прочитан, {len(data)} символов")
sys.exit(0)

Использование кода 2 для синтаксических ошибок - широко распространённая практика (например, в Unix-утилитах).

Как завершить интерпретатор в интерактивном режиме?

Встроенная функция exit() (без модуля sys) предназначена для удобства в интерактивной консоли. В скриптах её использовать не рекомендуется, так как она может быть переопределена или недоступна. При вызове exit() в интерактивном сеансе вызывается sys.exit(0).


# в интерактивной консоли:
>>> exit()

Для выхода с кодом ошибки в интерактивном режиме используйте sys.exit(1).

Распространённая ошибка - вызов exit() внутри функции, которая затем импортируется. Так как exit() является экземпляром класса Exit (в модуле _sitebuiltins), он может вести себя не так, как ожидается. Рекомендуется всегда использовать sys.exit() в коде, предназначенном для повторного использования.

Расширенные примеры работы с кодами выхода

Как использовать разные коды выхода для разных типов ошибок?

Пример

import sys

def process_file(filename):
    if not isinstance(filename, str):
        return 3  # неверный тип аргумента
    try:
        with open(filename) as f:
            pass
    except FileNotFoundError:
        return 1
    except PermissionError:
        return 2
    return 0

if __name__ == "__main__":
    import sys
    code = process_file(sys.argv[1] if len(sys.argv) > 1 else None)
    sys.exit(code)
# при запуске с несуществующим файлом код 1, с недоступным - 2, с неверным аргументом - 3

Как перехватить SystemExit для логирования перед завершением?

Пример

import sys
import logging

logging.basicConfig(level=logging.INFO)

try:
    # основной код
    if some_error:
        sys.exit(1)
except SystemExit as e:
    logging.warning(f"Программа завершается с кодом {e.code}")
    raise  # передаём исключение дальше
WARNING:root:Программа завершается с кодом 1
# после этого программа завершается с кодом 1

Как os._exit() используется в дочерних процессах после os.fork()?

Пример

import os
import sys

pid = os.fork()
if pid == 0:
    # дочерний процесс
    print("Дочерний процесс начинает")
    os._exit(42)  # немедленно завершаем
else:
    # родительский процесс
    child_pid, status = os.waitpid(pid, 0)
    exit_code = os.WEXITSTATUS(status)
    print(f"Дочерний процесс завершился с кодом {exit_code}")
Дочерний процесс начинает
Дочерний процесс завершился с кодом 42

Использование sys.exit() в дочернем процессе может вызвать выполнение блоков finally и повлиять на родительский процесс, поэтому os._exit() предпочтительнее.

Как получить код выхода внешней программы с помощью модуля subprocess?

Пример

import subprocess

# запуск программы и получение её кода возврата
result = subprocess.run(['python3', '-c', 'import sys; sys.exit(5)'], capture_output=True)
print(f"Код выхода: {result.returncode}")
Код выхода: 5

Если возвращаемый код выхода не равен нулю, можно обработать ошибку:

Пример

if result.returncode != 0:
    print(f"Ошибка: {result.stderr.decode()}")

Как гарантировать выполнение очистки даже при SystemExit?

Пример

import sys
import atexit

@atexit.register
def cleanup():
    print("Выполняется очистка")

# даже если вызван sys.exit, atexit выполнится
def main():
    print("Основной код")
    sys.exit(1)

if __name__ == "__main__":
    main()
Основной код
Выполняется очистка

Функции, зарегистрированные через atexit, выполняются до завершения интерпретатора, если только не используется os._exit().

Как сигналы влияют на код выхода?

Пример

import signal
import sys

def handler(signum, frame):
    print(f"Получен сигнал {signum}, завершаемся")
    sys.exit(128 + signum)  # стандартный код для сигналов

signal.signal(signal.SIGINT, handler)

while True:
    pass
# при нажатии Ctrl+C:
Получен сигнал 2, завершаемся
# программа завершается с кодом 130 (128+2)

Этот подход соответствует поведению многих утилит Unix.

Код выхода python 3 exit - comments

En
Python 3 exit (python)