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