Режим разработки Python
Новая версия 3.7.
Режим разработки Python добавляет дополнительные проверки во время выполнения, которые слишком затратны, чтобы их включать по умолчанию. Он не должен быть более подробным, чем по умолчанию, если код корректен; новые предупреждения выводятся только при обнаружении проблемы.
Его можно включить, используя опцию командной строки -X dev или задав переменную окружения PYTHONDEVMODE со значением 1.
См. также Отладочная сборка Python.
Воздействие режима разработки Python
Включение режима разработки Python аналогично следующей команде, но с дополнительными эффектами, описанными ниже:
PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python3 -W default -X faulthandler
Воздействие режима разработки Python:
-
Добавить
defaultфильтр предупреждений. Будут отображаться следующие предупреждения:Обычно вышеперечисленные предупреждения отфильтровываются стандартными фильтрами предупреждений.
Ведёт себя так, как если бы использовалась опция командной строки
-W default.Используйте опцию командной строки
-W errorили задайте переменную окруженияPYTHONWARNINGSсо значениемerrorдля обработки предупреждений как ошибок. -
Установка отладочных обработчиков на выделения памяти для проверки:
- Недопустимое уменьшение буфера
- Недопустимое увеличение буфера
- Нарушение 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проверяет сопрограммы, которые не были ожидаемы, и регистрирует их.Ведёт себя так, как если бы переменная окружения
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. Явное закрытие ресурсов делает приложение более детерминированным и надёжным.
Пример ошибки «Bad file descriptor»
Скрипт, отображающий первую строку самого себя:
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 -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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/devmode.html