Python. Завершение программ

:book: Марк Лутц, Программирование на Python, том I, стр.309

Завершение программ средствами модуля sys

Например, программу можно завершить раньше обычного, вызвав функцию sys.exit:

sys.exit(N) # выход с кодом завершения N, в противном случае
            # программа завершится по достижении конца сценария

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

import sys
try:
...
 sys.exit()  # см. также: os._exit, Tk().quit()
... except SystemExit:
...
 print('ignoring exit')
...
ignoring exit

Завершение программ средствами модуля os

Можно выйти из Python и другими способами. Например, в дочернем процессе в Unix обычно вызывается функция os._exit, а не sys.exit. Потоки можно завершать с помощью функции _thread.exit, а приложения с графическим интерфейсом на основе tkinter часто завершаются с помощью метода Тк().quit().

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

modul_bye.py

def bye():
    import os
    print('Bye world')
    os._exit(99)
    print('Never reached')

if __name__ ##### '__main__': bye()
python3 modul_bye.py" 
Bye world

В отличие от sys.exit, функция os._exit неуязвима для инструкций обработки исключений try/except и try/finally:

bye_try_exc.py

from modul_bye import bye

try:
    bye()
except:
    print('This text will be ignored')
python3 bye_try_exc.py" 
Bye world

bye_try_fin.py

from modul_bye import bye

try:
    bye()
finally:
    print('This text will be ignored')
python3 bye_try_fin.py" 
Bye world

Повышаем надежность с contextlib

Для классов, которые не приспособлены для работы с with есть функция closing в библиотеке contextlib. Из документации:

Этот код…

with closing(<module>.open(<arguments>)) as f:
    <block>

…эквивалентный этому:

f = <module>.open(<arguments>)
try:
    <block>
finally:
    f.close()

Вот небольшой пример работы этой функции:

import contextlib

class Closeable:
    def close(self):
        print('closed')

with contextlib.closing(Closeable()):
    pass

# печатает closed

Теперь небольшое отступление о том, почему стоит использовать конструкцию with.

Известно, что программа завершится от любого необработанного исключения, а не только от SystemExit. Таким образом, если в вашем коде используются какие-то ресурсы, которые требуется правильным образом закрывать перед завершением работы, нужно оборачивать работу с ними в блоки try … finally ….

Однако, при использовании конструкции with это оборачивание происходит автоматически, и все ресурсы закрываются корректно.

Так как выход из программы — это всего лишь брошенное исключение, то и в случае использования функции sys.exit закрытие открытых в операторе with ресурсов произойдёт корректно:

with contextlib.closing(Closeable()):
    sys.exit()

Вы можете писать также и свои классы, предоставляющие ресурсы или классы, оборачивающие другие, которые нужно уметь закрывать автоматически. Для этого используются методы enter и exit.