Python 開發模式

在 3.7 版被加入.

Python 開發模式引入了額外的 runtime 檢查,預設啟用這些檢查的成本太高。如果程式碼正確,它不應比預設值更詳細;僅當偵測到問題時才會發出新警告。

可以使用 -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 開發模式在最終化 (finalize) 檔案物件時顯示 ResourceWarning 並記錄 "Bad file descriptor" 錯誤:

$ 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 錯誤。檔案描述器只能關閉一次。在最壞的情況下,將它關閉兩次可能會導致崩潰 (crash)(相關範例請參閱 bpo-18748)。

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