Python 開發模式¶
在 3.7 版被加入.
Python 開發模式引入了額外的 runtime 檢查,預設啟用這些檢查的成本太高。如果程式碼正確,它不應比預設值更詳細;僅當偵測到問題時才會發出新警告。
可以使用-Xdev
命令列選項或將PYTHONDEVMODE
環境變數設為 1 來啟用它。
另請參閱Python 除錯建置。
Python 開發模式的影響¶
啟用 Python 開發模式類似以下指令,但具有如下所述的附加效果:
PYTHONMALLOC=debugPYTHONASYNCIODEBUG=1python-Wdefault-Xfaulthandler
Python 開發模式的效果:
新增
default
警告過濾器。以下警告會被顯示:一般來說,上述警告會被預設的警告過濾器給過濾掉。
它的行為就像使用
-Wdefault
命令列選項一樣。使用
-Werror
命令列選項或將PYTHONWARNINGS
環境變數設為error
會將警告視為錯誤。在記憶體分配器上安裝除錯 hook(掛鉤)以檢查:
緩衝區下溢 (underflow)
緩衝區溢位 (overflow)
記憶體分配器 API 違規
GIL 的不安全使用
請參閱
PyMem_SetupDebugHooks()
C 函式。它的行為就好像是將
PYTHONMALLOC
環境變數設定為debug
一樣。若要啟用 Python 開發模式而不在記憶體分配器上安裝偵錯 hook,請將
PYTHONMALLOC
環境變數設為default
。在 Python 啟動時呼叫
faulthandler.enable()
來為SIGSEGV
、SIGFPE
、SIGABRT
、SIGBUS
和SIGILL
訊號安裝處理函式以在當機時傾印 (dump) Python 回溯 (traceback)。它的行為就像使用
-Xfaulthandler
命令列選項或將PYTHONFAULTHANDLER
環境變數設定為1
。啟用asyncio 除錯模式。例如
asyncio
會檢查未被等待的 (not awaited) 協程並記錄 (log) 它們。它的行為就像將
PYTHONASYNCIODEBUG
環境變數設定為 1 一樣。檢查字串編碼和解碼操作的encoding 和errors 引數。例如:
open()
、str.encode()
和bytes.decode()
。預設情況下,為了獲得最佳效能,僅在第一個編碼/解碼錯誤時檢查errors 引數,並且有時會因為是空字串而忽略encoding 引數。
io.IOBase
解構函式會記錄close()
例外。
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 範例¶
計算命令列中指定的文字檔案列數的腳本範例:
importsysdefmain():fp=open(sys.argv[1])nlines=len(fp.readlines())print(nlines)# The file is closed implicitlyif__name__=="__main__":main()
該腳本不會明確關閉檔案。預設情況下,Python 不會發出任何警告。使用 README.txt 的範例,該檔案有 269 列:
$pythonscript.pyREADME.txt269
啟用 Python 開發模式會顯示ResourceWarning
警告:
$python-Xdevscript.pyREADME.txt269script.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-Xdev-Xtracemalloc=5script.pyREADME.rst269script.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])
修復方法是明確關閉該檔案。以下是使用情境管理器的範例:
defmain():# Close the file explicitly when exiting the with blockwithopen(sys.argv[1])asfp:nlines=len(fp.readlines())print(nlines)
不明確關閉資源可能會使資源開啟的時間比預期的長得多;它可能會在退出 Python 時導致嚴重問題。在 CPython 中很糟糕,但在 PyPy 中更糟。明確關閉資源使應用程式更具確定性和可靠性。
檔案描述器的錯誤範例¶
顯示自身第一列的腳本:
importosdefmain():fp=open(__file__)firstline=fp.readline()print(firstline.rstrip())os.close(fp.fileno())# The file is closed implicitlymain()
預設情況下,Python 不會發出任何警告:
$pythonscript.pyimport os
Python 開發模式在最終化 (finalize) 檔案物件時顯示ResourceWarning
並記錄 "Bad file descriptor" 錯誤:
$python-Xdevscript.pyimport osscript.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'> main()ResourceWarning: Enable tracemalloc to get the object allocation tracebackException 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) 嘗試再次關閉檔案描述器時,它會失敗並出現Badfiledescriptor
錯誤。檔案描述器只能關閉一次。在最壞的情況下,將它關閉兩次可能會導致崩潰 (crash)(相關範例請參閱bpo-18748)。
修復方法是刪除os.close(fp.fileno())
那列,或使用closefd=False
開啟檔案。