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 版本中的變化: 現在會對字串編碼和解碼操作的 *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 行

$ 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()) 關閉檔案描述符。當檔案物件終結器再次嘗試關閉檔案描述符時,它會因 Bad file descriptor 錯誤而失敗。檔案描述符必須只關閉一次。在最壞的情況下,關閉兩次可能導致崩潰(請參閱 bpo-18748 以獲取示例)。

修復方法是移除 os.close(fp.fileno()) 行,或者使用 closefd=False 開啟檔案。