Режим разработки Python
Добавлено в версии 3.7.
Режим разработки Python включает дополнительные проверки во время выполнения, которые слишком затратны, чтобы включать их по умолчанию. Если код написан правильно, он не должен приводить к большему количеству сообщений, чем режим по умолчанию; новые предупреждения появляются только при обнаружении проблемы.
Его можно включить с помощью параметра командной строки -X dev или задав для переменной окружения PYTHONDEVMODE значение 1.
См. также Отладочная сборка Python.
Эффекты режима разработки Python
Включение режима разработки Python аналогично следующей команде, но имеет и дополнительные эффекты, описанные ниже:
PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python -W default -X faulthandler
Эффекты режима разработки Python:
-
Добавляется
defaultфильтр предупреждений. Отображаются следующие предупреждения:Обычно перечисленные выше предупреждения отфильтровываются с помощью фильтров предупреждений по умолчанию.
Это действует так, как если бы был задан параметр командной строки
-W default.Используйте параметр командной строки
-W errorили задайте для переменной окруженияPYTHONWARNINGSзначениеerror, чтобы считать предупреждения ошибками. -
Устанавливаются отладочные перехватчики для аллокаторов памяти, позволяющие проверять:
- Выход за нижнюю границу буфера
- Выход за верхнюю границу буфера
- Нарушение API аллокатора памяти
- Небезопасное использование GIL
См. функцию C
PyMem_SetupDebugHooks().Это действует так, как если бы для переменной окружения
PYTHONMALLOCбыло задано значениеdebug.Чтобы включить режим разработки Python без установки отладочных перехватчиков для аллокаторов памяти, задайте для переменной окружения
PYTHONMALLOCзначениеdefault. -
При запуске Python вызывается
faulthandler.enable(), чтобы установить обработчики сигналовSIGSEGV,SIGFPE,SIGABRT,SIGBUSиSIGILL, которые выводят трассировку Python при аварийном завершении.Это действует так, как если бы был задан параметр командной строки
-X faulthandlerили для переменной окруженияPYTHONFAULTHANDLERбыло задано значение1. -
Включается режим отладки asyncio. Например,
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 не предотвращает удаление инструкций assert параметром командной строки -O и не препятствует присваиванию значения False переменной __debug__.
Режим разработки Python можно включить только при запуске Python. Его значение можно получить из sys.flags.dev_mode.
Изменено в версии 3.8: Деструктор io.IOBase теперь записывает исключения close() в журнал.
Изменено в версии 3.9: Теперь аргументы encoding и errors проверяются для операций кодирования и декодирования строк.
Пример ResourceWarning
Пример скрипта, подсчитывающего количество строк в текстовом файле, имя которого указано в командной строке:
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 строк:
$ 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():
# 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 не выдаёт никаких предупреждений:
$ python script.py import os
Режим разработки Python показывает предупреждение ResourceWarning и записывает в журнал ошибку «Недопустимый файловый дескриптор» при уничтожении файлового объекта:
$ 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.
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/devmode.html