Windows 上的 Python 常見問題¶
如何在 Windows 下執行 Python 程式?¶
這不一定是一個簡單的問題。如果您已經熟悉從 Windows 命令列執行程式,那麼一切都會顯得很明顯;否則,您可能需要一些額外的指導。
除非您使用某種整合開發環境,否則您最終會在被稱為“命令提示符視窗”中鍵入 Windows 命令。通常,您可以透過在搜尋欄中搜索 cmd
來建立一個這樣的視窗。您應該能夠識別何時啟動了這樣一個視窗,因為您會看到一個 Windows “命令提示符”,它通常看起來像這樣
C:\>
字母可能不同,後面可能還有其他內容,因此您也可能很容易看到類似這樣的內容
D:\YourName\Projects\Python>
這取決於您的計算機是如何設定的以及您最近還用它做了什麼。一旦您啟動了這樣一個視窗,您就離執行 Python 程式不遠了。
您需要意識到您的 Python 指令碼必須由另一個名為 Python 直譯器的程式處理。直譯器讀取您的指令碼,將其編譯成位元組碼,然後執行位元組碼來執行您的程式。那麼,您如何安排直譯器處理您的 Python 呢?
首先,您需要確保您的命令視窗將“py”這個詞識別為啟動直譯器的指令。如果您已經打開了一個命令視窗,您應該嘗試輸入命令 py
並按回車鍵
C:\Users\YourName> py
然後您應該會看到類似這樣的內容
Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
您已經在“互動模式”下啟動了直譯器。這意味著您可以互動式地輸入 Python 語句或表示式,並在您等待時執行或求值它們。這是 Python 最強大的功能之一。透過輸入一些您選擇的表示式並檢視結果來檢查它
>>> print("Hello")
Hello
>>> "Hello" * 3
'HelloHelloHello'
許多人將互動模式用作方便但高度可程式設計的計算器。當您想要結束互動式 Python 會話時,呼叫 exit()
函式或在輸入 Z 時按住 Ctrl 鍵,然後按 “Enter” 鍵以返回到您的 Windows 命令提示符。
您可能還會發現您有一個“開始”選單項,例如 >>>
提示符。如果是這樣,在您呼叫 exit()
函式或輸入 Ctrl-Z 字元後,該視窗將消失;Windows 在視窗中執行單個 “python” 命令,並在您終止直譯器時關閉它。
現在我們知道 py
命令已被識別,您可以將您的 Python 指令碼交給它。您必須提供 Python 指令碼的絕對路徑或相對路徑。假設您的 Python 指令碼位於您的桌面,名為 hello.py
,並且您的命令提示符已在您的主目錄中很好地開啟,因此您會看到類似於這樣的內容
C:\Users\YourName>
現在您將透過輸入 py
後跟您的指令碼路徑來要求 py
命令將您的指令碼交給 Python
C:\Users\YourName> py Desktop\hello.py
hello
如何使 Python 指令碼可執行?¶
在 Windows 上,標準的 Python 安裝程式已經將 .py 副檔名與檔案型別 (Python.File) 相關聯,併為該檔案型別提供了一個執行直譯器的開啟命令 (D:\Program Files\Python\python.exe "%1" %*
)。這足以使指令碼可以從命令提示符中作為 ‘foo.py’ 執行。如果您希望能夠透過簡單地鍵入 ‘foo’ 而不帶副檔名來執行指令碼,則需要將 .py 新增到 PATHEXT 環境變數中。
為什麼 Python 有時啟動需要很長時間?¶
通常,Python 在 Windows 上啟動非常快,但偶爾會出現 Python 突然開始需要很長時間才能啟動的錯誤報告。更令人困惑的是,Python 在其他配置相同的 Windows 系統上可以正常工作。
問題可能是由問題機器上的病毒檢查軟體配置錯誤引起的。已知某些病毒掃描程式在配置為監視來自檔案系統的所有讀取時,會引入兩個數量級的啟動開銷。嘗試檢查系統上的病毒掃描軟體的配置,以確保它們的配置確實相同。McAfee 在配置為掃描所有檔案系統讀取活動時尤其如此。
如何從 Python 指令碼建立一個可執行檔案?¶
有關可用於製作可執行檔案的工具列表,請參閱 如何從 Python 指令碼建立獨立的二進位制檔案?。
*.pyd
檔案與 DLL 相同嗎?¶
是的,.pyd 檔案是 dll,但有一些區別。如果您有一個名為 foo.pyd
的 DLL,那麼它必須有一個函式 PyInit_foo()
。然後您可以編寫 Python “import foo”,Python 將搜尋 foo.pyd(以及 foo.py,foo.pyc),如果找到它,將嘗試呼叫 PyInit_foo()
來初始化它。您不會將您的 .exe 與 foo.lib 連結,因為這會導致 Windows 要求 DLL 存在。
請注意,foo.pyd 的搜尋路徑是 PYTHONPATH,而不是 Windows 用於搜尋 foo.dll 的路徑。此外,foo.pyd 不需要存在即可執行您的程式,而如果您將程式與 dll 連結,則需要 dll。當然,如果您想說 import foo
,則需要 foo.pyd。在 DLL 中,連結在原始碼中使用 __declspec(dllexport)
宣告。在 .pyd 中,連結是在可用函式列表中定義的。
如何將 Python 嵌入到 Windows 應用程式中?¶
將 Python 直譯器嵌入到 Windows 應用程式中可以概括如下
不要直接將 Python 構建到您的 .exe 檔案中。在 Windows 上,Python 必須是一個 DLL,才能處理匯入本身就是 DLL 的模組。(這是第一個未記錄的關鍵事實。)相反,連結到
pythonNN.dll
;它通常安裝在C:\Windows\System
中。NN 是 Python 版本,一個數字,例如 Python 3.3 的 “33”。您可以透過兩種不同的方式連結到 Python。載入時連結意味著連結到
pythonNN.lib
,而執行時連結意味著連結到pythonNN.dll
。(一般說明:pythonNN.lib
是與pythonNN.dll
相對應的所謂“匯入 lib”。它僅為連結器定義符號。)執行時連結極大地簡化了連結選項;一切都在執行時發生。您的程式碼必須使用 Windows 的
LoadLibraryEx()
例程載入pythonNN.dll
。程式碼還必須使用 Windows 的GetProcAddress()
例程獲取的指標來訪問pythonNN.dll
中的例程和資料(即 Python 的 C API)。宏可以使使用這些指標對呼叫 Python C API 中例程的任何 C 程式碼都是透明的。如果您使用 SWIG,則可以輕鬆建立一個 Python“擴充套件模組”,使應用程式的資料和方法可供 Python 使用。SWIG 將為您處理幾乎所有繁瑣的細節。結果是您連結到 .exe 檔案中的 C 程式碼!您不必建立 DLL 檔案,這也簡化了連結。
SWIG 將建立一個 init 函式(一個 C 函式),其名稱取決於擴充套件模組的名稱。例如,如果模組的名稱為 leo,則 init 函式將被呼叫為 initleo()。如果您使用 SWIG 影子類,正如您應該的那樣,則 init 函式將被呼叫為 initleoc()。這將初始化一個主要由影子類使用的隱藏輔助類。
您可以在步驟 2 中將 C 程式碼連結到 .exe 檔案中的原因是,呼叫初始化函式等效於將模組匯入 Python! (這是第二個關鍵的未公開的事實。)
簡而言之,您可以使用以下程式碼來初始化帶有擴充套件模組的 Python 直譯器。
#include <Python.h> ... Py_Initialize(); // Initialize Python. initmyAppc(); // Initialize (import) the helper class. PyRun_SimpleString("import myApp"); // Import the shadow class.
如果使用 MSVC 以外的編譯器(用於構建 pythonNN.dll 的編譯器),Python 的 C API 會出現兩個問題,這將變得很明顯。
問題 1:所謂的“非常高階”函式接受
FILE *
引數,它們在多編譯器環境中不起作用,因為每個編譯器對struct FILE
的概念是不同的。從實現的角度來看,這些是非常底層的函式。問題 2:SWIG 在生成 void 函式的包裝器時會生成以下程式碼
Py_INCREF(Py_None); _resultobj = Py_None; return _resultobj;
唉,Py_None 是一個宏,它擴充套件為對 pythonNN.dll 內部名為 _Py_NoneStruct 的複雜資料結構的引用。同樣,此程式碼在多編譯器環境中將失敗。請將此類程式碼替換為
return Py_BuildValue("");
可以使用 SWIG 的
%typemap
命令自動進行更改,儘管我還沒有成功(我是一個完全的 SWIG 新手)。使用 Python shell 指令碼從您的 Windows 應用程式內部彈出 Python 直譯器視窗不是一個好主意;結果視窗將獨立於您的應用程式的視窗系統。相反,您(或 wxPythonWindow 類)應該建立一個“本機”直譯器視窗。將該視窗連線到 Python 直譯器很容易。您可以將 Python 的 i/o 重定向到支援讀取和寫入的任何物件,因此您只需要一個包含 read() 和 write() 方法的 Python 物件(在您的擴充套件模組中定義)。
如何防止編輯器在我的 Python 原始碼中插入製表符?¶
FAQ 不建議使用製表符,而 Python 樣式指南 PEP 8 建議將 4 個空格用於分散式 Python 程式碼;這也是 Emacs python-mode 的預設設定。
在任何編輯器下,混合使用製表符和空格都不是一個好主意。MSVC 在這方面也不例外,並且可以輕鬆配置為使用空格:選擇
,對於檔案型別“預設”,將“製表符大小”和“縮排大小”設定為 4,然後選擇“插入空格”單選按鈕。如果混合的製表符和空格導致前導空格出現問題,Python 將引發 IndentationError
或 TabError
。您也可以執行 tabnanny
模組以在批處理模式下檢查目錄樹。
如何在不阻塞的情況下檢查按鍵?¶
使用 msvcrt
模組。這是一個標準的 Windows 特定擴充套件模組。它定義了一個函式 kbhit()
,該函式檢查是否存在鍵盤按鍵,以及 getch()
,該函式獲取一個字元而不回顯它。
如何解決缺少 api-ms-win-crt-runtime-l1-1-0.dll 錯誤?¶
當在沒有安裝所有更新的 Windows 8.1 或更早版本上使用 Python 3.5 及更高版本時,可能會發生這種情況。首先確保您的作業系統受支援並且是最新的,如果這不能解決問題,請訪問 Microsoft 支援頁面,以獲取有關手動安裝 C 執行時更新的指導。