Документация Python неофициальный перевод
Содержание страницы

Режим разработки PythonPython Development Mode

Добавлено в версии 3.7.

Режим разработки Python добавляет дополнительные проверки во время выполнения, которые слишком ресурсоёмки, чтобы быть включёнными по умолчанию. Если код корректен, он не должен выводить больше сообщений, чем обычно; новые предупреждения появляются только при обнаружении проблемы.

Его можно включить с помощью опции командной строки -X dev или установив переменную окружения PYTHONDEVMODE в значение 1.

См. также отладочную сборку Python.

Эффекты режима разработки PythonEffects of the Python Development Mode

Включение режима разработки Python аналогично следующей команде, но с дополнительными эффектами, описанными ниже:

PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python -W default -X faulthandler

Эффекты режима разработки Python:

  • Добавляет default фильтр предупреждений. Отображаются следующие предупреждения:

    Обычно указанные выше предупреждения отфильтровываются стандартными фильтрами предупреждений.

    Поведение аналогично использованию опции командной строки -W default.

    Используйте опцию командной строки -W error или установите переменную окружения PYTHONWARNINGS в значение error, чтобы обрабатывать предупреждения как ошибки.

  • Устанавливает отладочные перехватчики на распределители памяти для проверки:

    • Опустошение буфера (buffer underflow)

    • Переполнение буфера

    • Нарушение API распределителя памяти

    • Небезопасное использование GIL

    См. функцию PyMem_SetupDebugHooks() на языке C.

    Поведение аналогично установке переменной окружения PYTHONMALLOC в значение debug.

    Чтобы включить режим разработки Python без установки отладочных перехватчиков на распределители памяти, установите переменную окружения PYTHONMALLOC в значение default.

  • Вызов faulthandler.enable() при запуске Python устанавливает обработчики для сигналов SIGSEGV, SIGFPE, SIGABRT, SIGBUS и SIGILL, чтобы выводить трассировку Python при сбое.

    Поведение аналогично использованию опции командной строки -X faulthandler или установке переменной окружения PYTHONFAULTHANDLER в значение 1.

  • Включает отладочный режим asyncio. Например, asyncio проверяет корутины, которые не были ожиданы (awaited), и регистрирует их.

    Поведение аналогично установке переменной окружения PYTHONASYNCIODEBUG в значение 1.

  • Проверяет аргументы encoding и errors для операций кодирования и декодирования строк. Примеры: open(), str.encode() и bytes.decode().

    По умолчанию для максимальной производительности аргумент errors проверяется только при первой ошибке кодирования/декодирования, а аргумент encoding иногда игнорируется для пустых строк.

  • Деструктор io.IOBase регистрирует исключения close().

  • Устанавливает атрибут dev_mode объекта sys.flags в значение True.

Режим разработки Python не включает модуль tracemalloc по умолчанию, поскольку накладные расходы (на производительность и память) были бы слишком велики. Включение модуля tracemalloc предоставляет дополнительную информацию о происхождении некоторых ошибок. Например, ResourceWarning регистрирует трассировку, где был выделен ресурс, а ошибка переполнения буфера регистрирует трассировку, где был выделен блок памяти.

Режим разработки Python не препятствует тому, чтобы опция командной строки -O удаляла операторы assert или устанавливала __debug__ в значение False.

Режим разработки Python может быть включён только при запуске Python. Его значение можно прочитать из sys.flags.dev_mode.

Изменено в версии 3.8: Деструктор io.IOBase теперь регистрирует исключения close().

Изменено в версии 3.9: Аргументы encoding и errors теперь проверяются для операций кодирования и декодирования строк.

Пример ResourceWarningResourceWarning Example

Пример сценария, подсчитывающего количество строк текстового файла, указанного в командной строке:

import sys

def main():
    fp = open(sys.argv[1])
    nlines = len(fp.readlines())
    print(nlines)
    # Файл закрывается неявно

if __name__ == "__main__":
    main()

Сценарий не закрывает файл явно. По умолчанию Python не выводит никаких предупреждений. Пример с файлом README.txt, который содержит 269 строк:

$ python script.py README.txt
269

Включение режима разработки Python отображает предупреждение ResourceWarning:

$ python -X dev script.py README.txt
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
  main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback

Кроме того, включение tracemalloc показывает строку, в которой файл был открыт:

$ python -X dev -X tracemalloc=5 script.py README.rst
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
  main()
Object allocated at (most recent call last):
  File "script.py", lineno 10
    main()
  File "script.py", lineno 4
    fp = open(sys.argv[1])

Исправление – явно закрыть файл. Пример с использованием контекстного менеджера:

def main():
    # Закрывать файл явно при выходе из блока with
    with open(sys.argv[1]) as fp:
        nlines = len(fp.readlines())
    print(nlines)

Явное незакрытие ресурса может оставить его открытым намного дольше, чем ожидалось; это может вызвать серьёзные проблемы при выходе из Python. Это плохо в CPython, но ещё хуже в PyPy. Явное закрытие ресурсов делает приложение более детерминированным и надёжным.

Пример ошибки «Bad file descriptor»Bad file descriptor error example

Сценарий, выводящий свою первую строку:

import os

def main():
    fp = open(__file__)
    firstline = fp.readline()
    print(firstline.rstrip())
    os.close(fp.fileno())
    # Файл закрывается неявно

main()

По умолчанию Python не выводит никаких предупреждений:

$ python script.py
import os

Режим разработки Python показывает ResourceWarning и регистрирует ошибку «Bad file descriptor» при финализации объекта файла:

$ python -X dev script.py
import os
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
  main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
Exception ignored in: <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
Traceback (most recent call last):
  File "script.py", line 10, in <module>
    main()
OSError: [Errno 9] Bad file descriptor

os.close(fp.fileno()) закрывает файловый дескриптор. Когда финализатор объекта файла пытается закрыть файловый дескриптор снова, это завершается ошибкой Bad file descriptor. Файловый дескриптор должен быть закрыт только один раз. В худшем случае повторное закрытие может привести к аварийному завершению (пример см. в bpo-18748).

Исправление – удалить строку os.close(fp.fileno()) или открыть файл с closefd=False.