Содержание страницы
Режим разработки Python¶Python Development Mode
Добавлено в версии 3.7.
Режим разработки Python добавляет дополнительные проверки во время выполнения, которые слишком ресурсоёмки, чтобы быть включёнными по умолчанию. Если код корректен, он не должен выводить больше сообщений, чем обычно; новые предупреждения появляются только при обнаружении проблемы.
Его можно включить с помощью опции командной строки -X dev или установив переменную окружения PYTHONDEVMODE в значение 1.
См. также отладочную сборку Python.
Эффекты режима разработки Python¶Effects 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 теперь проверяются для операций кодирования и декодирования строк.
Пример ResourceWarning¶ResourceWarning 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.