Перейти к содержимому

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

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

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

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

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

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

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

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

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

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

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

    Он ведёт себя так, как если бы была использована опция командной строки -W default.

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

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

    • Недостаток буфера (underflow)

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

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

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

    См. функцию C PyMem_SetupDebugHooks().

    Он ведёт себя так, как если бы переменная окружения 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 теперь проверяются для операций кодирования и декодирования строк.

ResourceWarning ExampleПример ResourceWarning

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

python
import sys

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

if __name__ == "__main__":
    main()

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

shell-session
$ python script.py README.txt
269

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

shell-session
$ 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 показывает строку, в которой файл был открыт:

shell-session
$ 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])

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

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

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

Bad file descriptor error exampleПример ошибки неверного файлового дескриптора

Скрипт, отображающий первую строку самого себя:

python
import os

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

main()

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

shell-session
$ python script.py
import os

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

shell-session
$ 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.