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.