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

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

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

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

Смотрите также Python debug build.

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

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

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

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

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

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

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

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

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

    • Недостаточный расход буфера

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

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

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

    Смотрите функцию PyMem_SetupDebugHooks() C.

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

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

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

    Он ведет себя так, как если бы использовался параметр командной строки -X faulthandler или если бы переменной окружения PYTHONFAULTHANDLER было присвоено значение 1.

  • Включите asyncio debug mode. Например, asyncio проверяет наличие сопрограмм, которые не ожидались, и регистрирует их.

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

Пример предупреждения о ресурсах

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

import sys

def main():
    fp = open(sys.argv[1])
    nlines = len(fp.readlines())
    print(nlines)
    # The file is closed implicitly

if __name__ == "__main__":
    main()

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

$ python3 script.py README.txt
269

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

$ python3 -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 отображается строка, в которой был открыт файл:

$ python3 -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():
    # Close the file explicitly when exiting the with block
    with open(sys.argv[1]) as fp:
        nlines = len(fp.readlines())
    print(nlines)

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

Пример ошибки с неверным файловым дескриптором

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

import os

def main():
    fp = open(__file__)
    firstline = fp.readline()
    print(firstline.rstrip())
    os.close(fp.fileno())
    # The file is closed implicitly

main()

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

$ python3 script.py
import os

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

$ python3 -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.

Вернуться на верх