Режим разработки Python¶
Добавлено в версии 3.7.
Режим разработки Python вводит дополнительные проверки времени выполнения, которые слишком дороги, чтобы быть включенными по умолчанию. Он не должен быть более многословным, чем по умолчанию, если код корректен; новые предупреждения выдаются только при обнаружении проблемы.
Его можно включить с помощью опции командной строки -X dev или установив переменную окружения PYTHONDEVMODE в значение 1.
См. также Python debug build.
Эффекты режима разработки Python¶
Включение режима разработки Python аналогично следующей команде, но с дополнительными эффектами, описанными ниже:
PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python3 -W default -X faulthandler
Эффекты режима разработки Python:
Добавьте
defaultwarning 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 теперь проверяются для операций кодирования и декодирования строк.
Пример 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 строк:
$ 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 и регистрирует ошибку «Bad file descriptor» при завершении работы с файловым объектом:
$ python3 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.