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() 函式或按住 Ctrl 鍵並輸入 Z,然後按“Enter”鍵返回到你的 Windows 命令提示符。

你可能還會發現有一個開始選單條目,例如 開始 ‣ 程式 ‣ Python 3.x ‣ Python(命令列),這會導致你在新視窗中看到 >>> 提示符。如果是這樣,在呼叫 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 應用程式可以概括如下

  1. 不要 將 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 對應的所謂“匯入庫”。它僅為連結器定義符號。)

    執行時連結大大簡化了連結選項;一切都在執行時發生。你的程式碼必須使用 Windows LoadLibraryEx() 例程載入 pythonNN.dll。程式碼還必須使用透過 Windows GetProcAddress() 例程獲得的指標訪問 pythonNN.dll 中的訪問例程和資料(即 Python 的 C API)。宏可以使任何呼叫 Python C API 中例程的 C 程式碼透明地使用這些指標。

  2. 如果你使用 SWIG,可以輕鬆建立 Python“擴充套件模組”,從而使應用程式的資料和方法可供 Python 使用。SWIG 會為你處理幾乎所有繁瑣的細節。結果是 C 程式碼,你將其 連結 到你的 .exe 檔案中(!)你不必建立 DLL 檔案,這也簡化了連結。

  3. SWIG 將建立一個 init 函式(一個 C 函式),其名稱取決於擴充套件模組的名稱。例如,如果模組的名稱是 leo,則 init 函式將被稱為 initleo()。如果你使用 SWIG 陰影類,你應該這樣做,init 函式將被稱為 initleoc()。這會初始化陰影類使用的幾乎隱藏的輔助類。

    你可以在步驟 2 中將 C 程式碼連結到 .exe 檔案中的原因是,呼叫初始化函式等同於將模組匯入到 Python 中!(這是第二個關鍵的未文件化事實。)

  4. 簡而言之,你可以使用以下程式碼透過你的擴充套件模組初始化 Python 直譯器。

    #include <Python.h>
    ...
    Py_Initialize();  // Initialize Python.
    initmyAppc();  // Initialize (import) the helper class.
    PyRun_SimpleString("import myApp");  // Import the shadow class.
    
  5. Python 的 C API 有兩個問題,如果你使用 MSVC 以外的編譯器(用於構建 pythonNN.dll 的編譯器),這些問題將變得顯而易見。

    問題 1:接受 FILE * 引數的所謂“極高級”函式在多編譯器環境中將不起作用,因為每個編譯器對 struct FILE 的概念都不同。從實現的角度來看,這些是非常低階的函式。

    問題 2:當為 void 函式生成包裝器時,SWIG 會生成以下程式碼

    Py_INCREF(Py_None);
    _resultobj = Py_None;
    return _resultobj;
    

    唉,Py_None 是一個宏,它擴充套件為對 pythonNN.dll 中名為 _Py_NoneStruct 的複雜資料結構的引用。同樣,此程式碼在多編譯器環境中會失敗。將此類程式碼替換為

    return Py_BuildValue("");
    

    可能可以使用 SWIG 的 %typemap 命令自動進行更改,儘管我尚未成功實現(我是一個完全的 SWIG 新手)。

  6. 從你的 Windows 應用程式內部使用 Python shell 指令碼彈出一個 Python 直譯器視窗不是一個好主意;生成的視窗將獨立於你的應用程式的視窗系統。相反,你(或 wxPythonWindow 類)應該建立一個“原生”直譯器視窗。將該視窗連線到 Python 直譯器很容易。你可以將 Python 的 I/O 重定向到支援讀寫的_任何_物件,所以你只需要一個包含 read() 和 write() 方法的 Python 物件(在你的擴充套件模組中定義)。

如何防止編輯器在我的 Python 原始檔中插入製表符?

常見問題解答不建議使用製表符,Python 風格指南 PEP 8 建議對分發的 Python 程式碼使用 4 個空格;這也是 Emacs python-mode 的預設設定。

在任何編輯器中,混用製表符和空格都不是一個好主意。MSVC 在這方面也不例外,並且很容易配置為使用空格:選擇 工具 ‣ 選項 ‣ 製表符,對於檔案型別“預設”,將“製表符大小”和“縮排大小”設定為 4,並選擇“插入空格”單選按鈕。

如果混合製表符和空格在引導空白中導致問題,Python 會引發 IndentationErrorTabError。你還可以執行 tabnanny 模組以批處理模式檢查目錄樹。

如何檢查按鍵而不阻塞?

使用 msvcrt 模組。這是一個標準的 Windows 專用擴充套件模組。它定義了一個函式 kbhit() 用於檢查是否有按鍵存在,以及 getch() 用於獲取一個字元而不回顯它。

如何解決 api-ms-win-crt-runtime-l1-1-0.dll 缺失錯誤?

這可能發生在 Python 3.5 及更高版本在使用 Windows 8.1 或更早版本且未安裝所有更新時。首先確保你的作業系統受支援且已更新,如果這不能解決問題,請訪問 Microsoft 支援頁面 以獲取手動安裝 C 執行時更新的指導。