Python开发模式¶
3.7 新版功能.
Python开发模式引入了额外的运行时检查,这些检查在默认情况下过于昂贵,无法启用。如果代码正确,则不应比默认值更详细;只有在检测到问题时才会发出新警告。
可以使用 -X dev
命令行选项或通过设置 PYTHONDEVMODE
环境变量到 1
.
Python开发模式的效果¶
启用Python开发模式类似于以下命令,但具有以下所述的附加效果:
PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python3 -W default -X faulthandler
Python开发模式的效果:
添加
default
warning 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
.检查 编码 和 错误 字符串编码和解码操作的参数。示例:
open()
,str.encode()
和bytes.decode()
.默认情况下,为了获得最佳性能 错误 参数只在第一个编码/解码错误和 编码 对于空字符串,有时忽略参数。
这个
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 版更改: 这个 编码 和 错误 现在检查参数是否有字符串编码和解码操作。
资源警告示例¶
计算命令行中指定的文本文件行数的脚本示例:
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 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
.