Режим разработки на 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 теперь проверяются для операций кодирования и декодирования строк.
Пример предупреждения о ресурсах¶
Пример скрипта, подсчитывающего количество строк текстового файла, указанного в командной строке:
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.