> **Источник:** https://python-all.ru/2.7/library/signal.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 17.4. [`signal`](https://python-all.ru/2.7/library/signal.html#module-signal) – Установка обработчиков для асинхронных событий

Этот модуль предоставляет механизмы для использования обработчиков сигналов в Python. Несколько общих правил работы с сигналами и их обработчиками:

- Обработчик конкретного сигнала после установки остается активным до явной переустановки (Python эмулирует интерфейс в стиле BSD независимо от реализации), за исключением обработчика для `SIGCHLD`, который следует базовой реализации.
- Нет способа временно «блокировать» сигналы в критических секциях (поскольку это поддерживается не во всех разновидностях Unix).
- Хотя с точки зрения пользователя Python обработчики сигналов вызываются асинхронно, они могут возникнуть только между «атомарными» инструкциями интерпретатора Python. Это означает, что сигналы, поступающие во время длительных вычислений, реализованных чисто на C (например, при сопоставлении регулярных выражений с большими объёмами текста), могут быть задержаны на произвольное время.
- Когда сигнал поступает во время операции ввода-вывода, возможно, что после возврата из обработчика сигнала операция ввода-вывода возбудит исключение. Это зависит от семантики прерывания системных вызовов в конкретной Unix-системе.
- Поскольку обработчик сигналов на C всегда возвращает управление, нет смысла перехватывать синхронные ошибки, такие как `SIGFPE` или `SIGSEGV`.
- Python по умолчанию устанавливает небольшое количество обработчиков сигналов: `SIGPIPE` игнорируется (поэтому ошибки записи в каналы и сокеты могут сообщаться как обычные исключения Python), а `SIGINT` преобразуется в исключение [`KeyboardInterrupt`](https://python-all.ru/2.7/library/exceptions.html#exceptions.KeyboardInterrupt). Все они могут быть переопределены.
- Следует соблюдать осторожность, если в одной программе используются и сигналы, и потоки. Основное правило при одновременном использовании сигналов и потоков: всегда выполняйте операции [`signal()`](https://python-all.ru/2.7/library/signal.html#module-signal) в главном потоке выполнения. Любой поток может выполнить [`alarm()`](https://python-all.ru/2.7/library/signal.html#signal.alarm), [`getsignal()`](https://python-all.ru/2.7/library/signal.html#signal.getsignal), [`pause()`](https://python-all.ru/2.7/library/signal.html#signal.pause), [`setitimer()`](https://python-all.ru/2.7/library/signal.html#signal.setitimer) или [`getitimer()`](https://python-all.ru/2.7/library/signal.html#signal.getitimer); только главный поток может установить новый обработчик сигнала, и только главный поток будет получать сигналы (это обеспечивается модулем [`signal`](https://python-all.ru/2.7/library/signal.html#module-signal) Python, даже если базовая реализация потоков поддерживает отправку сигналов отдельным потокам). Это означает, что сигналы нельзя использовать как средство межпотокового взаимодействия. Вместо этого используйте блокировки.

Переменные, определенные в модуле [`signal`](https://python-all.ru/2.7/library/signal.html#module-signal):

#### `signal.SIG_DFL`

Это один из двух стандартных вариантов обработки сигналов; он просто выполняет функцию по умолчанию для сигнала. Например, на большинстве систем действие по умолчанию для `SIGQUIT` – сбросить дамп ядра и завершиться, тогда как действие по умолчанию для `SIGCHLD` – просто игнорировать его.

#### `signal.SIG_IGN`

Это еще один стандартный обработчик сигнала, который просто игнорирует данный сигнал.

#### `SIG*`

Все номера сигналов определены символически. Например, сигнал разъединения (hangup) определяется как `signal.SIGHUP`; имена переменных совпадают с именами, используемыми в программах на C, которые можно найти в `<signal.h>`. Страница руководства Unix для «`signal()`» перечисляет существующие сигналы (в некоторых системах это *signal(2)*, в других список находится в *signal(7)*). Обратите внимание, что не все системы определяют один и тот же набор имен сигналов; модуль определяет только те имена, которые определены системой.

#### `signal.CTRL_C_EVENT`

Сигнал, соответствующий нажатию клавиши `Ctrl+C`. Этот сигнал можно использовать только с [`os.kill()`](https://python-all.ru/2.7/library/os.html#os.kill).

Доступность: Windows.

Новое в версии 2.7.

#### `signal.CTRL_BREAK_EVENT`

Сигнал, соответствующий нажатию клавиши `Ctrl+Break`. Этот сигнал можно использовать только с [`os.kill()`](https://python-all.ru/2.7/library/os.html#os.kill).

Доступность: Windows.

Новое в версии 2.7.

#### `signal.NSIG`

На единицу больше номера самого высокого сигнала.

#### `signal.ITIMER_REAL`

Уменьшает интервальный таймер в реальном времени и доставляет `SIGALRM` по истечении.

#### `signal.ITIMER_VIRTUAL`

Уменьшает интервальный таймер только во время выполнения процесса и отправляет SIGVTALRM по истечении.

#### `signal.ITIMER_PROF`

Уменьшает интервальный таймер как при выполнении процесса, так и при выполнении системой от имени процесса. В паре с ITIMER\_VIRTUAL этот таймер обычно используется для профилирования времени, затраченного приложением в пользовательском и ядерном пространстве. SIGPROF доставляется по истечении времени.

Модуль [`signal`](https://python-all.ru/2.7/library/signal.html#module-signal) определяет одно исключение:

#### `exception signal.ItimerError`

Возбуждается для указания на ошибку в реализации [`setitimer()`](https://python-all.ru/2.7/library/signal.html#signal.setitimer) или [`getitimer()`](https://python-all.ru/2.7/library/signal.html#signal.getitimer). Этого исключения следует ожидать, если некорректный интервальный таймер или отрицательное время передаются в [`setitimer()`](https://python-all.ru/2.7/library/signal.html#signal.setitimer). Это исключение является подтипом [`IOError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.IOError).

Модуль [`signal`](https://python-all.ru/2.7/library/signal.html#module-signal) определяет следующие функции:

#### `signal.alarm(time)`

Если *time* не равно нулю, эта функция запрашивает отправку сигнала `SIGALRM` процессу через *time* секунд. Любая ранее запланированная тревога отменяется (одновременно может быть запланирована только одна тревога). Возвращаемое значение – количество секунд до момента, когда должна была быть доставлена предыдущая тревога. Если *time* равно нулю, тревога не планируется, а любая запланированная отменяется. Если возвращаемое значение равно нулю, текущая тревога не запланирована. (См. страницу руководства Unix *alarm(2)*.) Доступность: Unix.

#### `signal.getsignal(signalnum)`

Возвращает текущий обработчик сигнала *signalnum*. Возвращаемое значение может быть вызываемым объектом Python или одним из специальных значений [`signal.SIG_IGN`](https://python-all.ru/2.7/library/signal.html#signal.SIG_IGN), [`signal.SIG_DFL`](https://python-all.ru/2.7/library/signal.html#signal.SIG_DFL) или [`None`](https://python-all.ru/2.7/library/constants.html#None). Здесь [`signal.SIG_IGN`](https://python-all.ru/2.7/library/signal.html#signal.SIG_IGN) означает, что сигнал ранее игнорировался, [`signal.SIG_DFL`](https://python-all.ru/2.7/library/signal.html#signal.SIG_DFL) означает, что ранее использовался способ обработки сигнала по умолчанию, а `None` означает, что предыдущий обработчик сигнала не был установлен из Python.

#### `signal.pause()`

Заставляет процесс спать до получения сигнала; затем будет вызван соответствующий обработчик. Ничего не возвращает. Недоступно в Windows. (См. страницу руководства Unix *signal(2)*.)

#### `signal.setitimer(which, seconds[, interval])`

Устанавливает заданный интервальный таймер (один из [`signal.ITIMER_REAL`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_REAL), [`signal.ITIMER_VIRTUAL`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_VIRTUAL) или [`signal.ITIMER_PROF`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_PROF)), указанный через *which*, для срабатывания через *seconds* секунд (допускается число с плавающей точкой, в отличие от [`alarm()`](https://python-all.ru/2.7/library/signal.html#signal.alarm)) и затем каждые *interval* секунд. Интервальный таймер, указанный через *which*, можно сбросить, установив seconds в ноль.

Когда срабатывает интервальный таймер, процессу отправляется сигнал. Отправляемый сигнал зависит от используемого таймера: [`signal.ITIMER_REAL`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_REAL) доставляет `SIGALRM`, [`signal.ITIMER_VIRTUAL`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_VIRTUAL) отправляет `SIGVTALRM`, а [`signal.ITIMER_PROF`](https://python-all.ru/2.7/library/signal.html#signal.ITIMER_PROF) доставляет `SIGPROF`.

Старые значения возвращаются в виде кортежа: (delay, interval).

Попытка передать недопустимый интервальный таймер вызовет [`ItimerError`](https://python-all.ru/2.7/library/signal.html#signal.ItimerError). Доступность: Unix.

Новое в версии 2.6.

#### `signal.getitimer(which)`

Возвращает текущее значение указанного интервального таймера, заданного через *which*. Доступность: Unix.

Новое в версии 2.6.

#### `signal.set_wakeup_fd(fd)`

Устанавливает fd пробуждения в *fd*. Когда получен сигнал, в fd записывается один `'\0'` байт. Это может использоваться библиотекой для пробуждения вызова poll или select, чтобы сигнал был полностью обработан.

Возвращается старый fd пробуждения (или -1, если пробуждение через файловый дескриптор не было включено). Если *fd* равен -1, пробуждение через файловый дескриптор отключается. Если не -1, то *fd* должен быть неблокирующим. Задача библиотеки – удалить все байты из *fd* перед повторным вызовом poll или select.

Когда потоки включены, эту функцию можно вызывать только из главного потока; попытка вызова из других потоков приведет к возникновению исключения [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError).

Новое в версии 2.6.

#### `signal.siginterrupt(signalnum, flag)`

Изменяет поведение перезапуска системных вызовов: если *flag* равно [`False`](https://python-all.ru/2.7/library/constants.html#False), системные вызовы будут перезапущены при прерывании сигналом *signalnum*, в противном случае системные вызовы будут прерваны. Ничего не возвращает. Доступность: Unix (см. страницу руководства *siginterrupt(3)* для получения дополнительной информации).

Обратите внимание, что установка обработчика сигнала с помощью [`signal()`](https://python-all.ru/2.7/library/signal.html#module-signal) сбрасывает поведение перезапуска на прерываемое, неявно вызывая `siginterrupt()` со значением *flag*, равным true, для данного сигнала.

Новое в версии 2.6.

#### `signal.signal(signalnum, handler)`

Устанавливает обработчик для сигнала *signalnum* равным функции *handler*. *handler* может быть вызываемым объектом Python, принимающим два аргумента (см. ниже), или одним из специальных значений [`signal.SIG_IGN`](https://python-all.ru/2.7/library/signal.html#signal.SIG_IGN) или [`signal.SIG_DFL`](https://python-all.ru/2.7/library/signal.html#signal.SIG_DFL). Возвращается предыдущий обработчик сигнала (см. описание [`getsignal()`](https://python-all.ru/2.7/library/signal.html#signal.getsignal) выше). (См. страницу руководства Unix *signal(2)*).

Когда потоки включены, эту функцию можно вызывать только из главного потока; попытка вызова из других потоков приведет к возникновению исключения [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError).

*handler* вызывается с двумя аргументами: номером сигнала и текущим стековым кадром (`None` или объектом кадра; описание объектов кадра см. в [описании в иерархии типов](https://python-all.ru/2.7/reference/datamodel.html#frame-objects) или в описаниях атрибутов модуля [`inspect`](https://python-all.ru/2.7/library/inspect.html#module-inspect)).

В Windows [`signal()`](https://python-all.ru/2.7/library/signal.html#module-signal) можно вызывать только с `SIGABRT`, `SIGFPE`, `SIGILL`, `SIGINT`, `SIGSEGV` или `SIGTERM`. В любом другом случае будет возбуждено [`ValueError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ValueError).

## 17.4.1. Пример

Вот минимальный пример программы. Она использует функцию [`alarm()`](https://python-all.ru/2.7/library/signal.html#signal.alarm) для ограничения времени, затрачиваемого на ожидание открытия файла; это полезно, если файл находится на последовательном устройстве, которое может быть выключено, что обычно приводит к бесконечному зависанию [`os.open()`](https://python-all.ru/2.7/library/os.html#os.open). Решение – установить 5-секундный будильник перед открытием файла; если операция занимает слишком много времени, будет отправлен сигнал будильника, и обработчик возбудит исключение.

```python
import signal, os

def handler(signum, frame):
    print 'Signal handler called with signal', signum
    raise IOError("Couldn't open device!")

# Установить обработчик сигнала и 5-секундный будильник
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# Этот вызов open() может зависнуть навсегда
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Отключить будильник
```
