Python 开发模式

3.7 版本新增。

Python 开发模式引入了额外的运行时检查,这些检查的开销太大,默认情况下不启用。如果代码正确,它不应该比默认情况更冗长;只有在检测到问题时才会发出新的警告。

可以使用 -X dev 命令行选项启用它,或者将 PYTHONDEVMODE 环境变量设置为 1

另请参阅 Python 调试版本

Python 开发模式的效果

启用 Python 开发模式类似于以下命令,但具有下面描述的附加效果

PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python -W default -X faulthandler

Python 开发模式的效果

默认情况下,Python 开发模式不会启用 tracemalloc 模块,因为开销成本(对性能和内存)会太大。启用 tracemalloc 模块可以提供有关某些错误的来源的附加信息。例如,ResourceWarning 会记录资源分配的回溯,而缓冲区溢出错误会记录内存块分配的回溯。

Python 开发模式不会阻止 -O 命令行选项删除 assert 语句,也不会阻止将 __debug__ 设置为 False

Python 开发模式只能在 Python 启动时启用。其值可以从 sys.flags.dev_mode 读取。

在 3.8 版本中更改: io.IOBase 析构函数现在记录 close() 异常。

在 3.9 版本中更改: 现在会检查字符串编码和解码操作的 encodingerrors 参数。

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 行

$ 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():
    # 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 不会发出任何警告

$ python script.py
import os

Python 开发模式会显示 ResourceWarning,并在最终确定文件对象时记录 “错误的文件描述符” 错误

$ 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()) 关闭文件描述符。当文件对象 finalizer 再次尝试关闭文件描述符时,它会因 Bad file descriptor 错误而失败。文件描述符只能关闭一次。在最坏的情况下,关闭两次可能会导致崩溃(例如,请参阅 bpo-18748)。

修复方法是删除 os.close(fp.fileno()) 行,或使用 closefd=False 打开文件。