Python在Windows上的常見問題?

我怎樣在Windows下運(yùn)行一個(gè)Python程序??

這不一定是一個(gè)簡(jiǎn)單的問題。如果你已經(jīng)熟悉在Windows的命令行中運(yùn)行程序的方法,一切都顯而易見;不然的話,你也許需要額外獲得些許指導(dǎo)。

Unless you use some sort of integrated development environment, you will end up typing Windows commands into what is referred to as a "Command prompt window". Usually you can create such a window from your search bar by searching for cmd. You should be able to recognize when you have started such a window because you will see a Windows "command prompt", which usually looks like this:

C:\>

前面的字母可能會(huì)不同,而且后面有可能會(huì)有其他東西,所以你也許會(huì)看到類似這樣的東西:

D:\YourName\Projects\Python>

出現(xiàn)的內(nèi)容具體取決與你的電腦如何設(shè)置和最近用它做的事。 當(dāng)你啟動(dòng)了這樣一個(gè)窗口后,就可以開始運(yùn)行Python程序了。

Python 腳本需要被另外一個(gè)叫做 Python 解釋器 的程序來處理。 解釋器讀取腳本,把它編譯成字節(jié)碼,然后執(zhí)行字節(jié)碼來運(yùn)行你的程序。 所以怎樣安排解釋器來處理你的 Python 腳本呢?

首先,確保命令窗口能夠?qū)ⅰ皃y”識(shí)別為指令來開啟解釋器。 如果你打開過一個(gè)命令窗口, 嘗試輸入命令 py 然后按回車:

C:\Users\YourName> py

然后你應(yīng)當(dāng)看見類似類似這樣的東西:

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.
>>>

解釋器已經(jīng)以“交互模式”打開。這意味著你可以交互輸入Python語句或表達(dá)式,并在等待時(shí)執(zhí)行或評(píng)估它們。這是Python最強(qiáng)大的功能之一。輸入幾個(gè)表達(dá)式并看看結(jié)果:

>>>
>>> print("Hello")
Hello
>>> "Hello" * 3
'HelloHelloHello'

許多人把交互模式當(dāng)作方便和高度可編程的計(jì)算器。 想結(jié)束交互式Python會(huì)話時(shí),調(diào)用 exit() 函數(shù),或者按住 Ctrl 鍵時(shí)輸入 Z ,之后按 Enter 鍵返回Windows命令提示符。

你可能發(fā)現(xiàn)在開始菜單有這樣一個(gè)條目 開始 ? 所有程序 ? Python 3.x ? Python (命令行), 運(yùn)行它后會(huì)出現(xiàn)一個(gè)有著 >>> 提示的新窗口。 在此之后,如果調(diào)用 exit() 函數(shù)或按 Ctrl-Z 組合鍵后窗口將會(huì)消失。 Windows 會(huì)在這個(gè)窗口中運(yùn)行一個(gè)“python”命令,并且在你終止解釋器的時(shí)候關(guān)閉它。

現(xiàn)在我們知道 py 命令已經(jīng)被識(shí)別,可以輸入 Python 腳本了。 你需要提供 Python 腳本的絕對(duì)路徑或相對(duì)路徑。 假設(shè) Python 腳本位于桌面上并命名為 hello.py,并且命令提示符在用戶主目錄打開,那么可以看到類似于這樣的東西:

C:\Users\YourName>

那么現(xiàn)在可以讓 py 命令執(zhí)行你的腳本,只需要輸入 py 和腳本路徑:

C:\Users\YourName> py Desktop\hello.py
hello

我怎么讓 Python 腳本可執(zhí)行??

在 Windows 上,標(biāo)準(zhǔn) Python 安裝程序已將 .py 擴(kuò)展名與文件類型 (Python.File) 相關(guān)聯(lián),并為該文件類型提供運(yùn)行解釋器的打開命令 (D:\Program Files\Python\python.exe "%1" %*) 。 這足以使腳本在命令提示符下作為“foo.py”命令被執(zhí)行。 如果希望通過簡(jiǎn)單地鍵入“foo”而無需輸入文件擴(kuò)展名來執(zhí)行腳本,則需要將 .py 添加到 PATHEXT 環(huán)境變量中。

為什么有時(shí)候 Python 程序會(huì)啟動(dòng)緩慢??

通常,Python 在 Windows 上啟動(dòng)得很快,但偶爾會(huì)有錯(cuò)誤報(bào)告說 Python 突然需要很長(zhǎng)時(shí)間才能啟動(dòng)。更令人費(fèi)解的是,在其他配置相同的 Windows 系統(tǒng)上,Python 卻可以工作得很好。

該問題可能是由于計(jì)算機(jī)上的殺毒軟件配置錯(cuò)誤造成的。當(dāng)將病毒掃描配置為監(jiān)視文件系統(tǒng)中所有讀取行為時(shí),一些殺毒掃描程序會(huì)導(dǎo)致兩個(gè)數(shù)量級(jí)的啟動(dòng)開銷。請(qǐng)檢查你系統(tǒng)安裝的殺毒掃描程序的配置,確保兩臺(tái)機(jī)它們是同樣的配置。已知的, McAfee 殺毒軟件在將它設(shè)置為掃描所有文件系統(tǒng)訪問時(shí),會(huì)產(chǎn)生這個(gè)問題。

我怎樣使用 Python 腳本制作可執(zhí)行文件??

請(qǐng)參閱 如何由 Python 腳本創(chuàng)建能獨(dú)立運(yùn)行的二進(jìn)制程序? 查看可用來生成可執(zhí)行文件的工具清單。

*.pyd 文件和 DLL 文件相同嗎??

是的, .pyd 文件也是 dll ,但有一些差異。如果你有一個(gè)名為 foo.pyd 的DLL,那么它必須有一個(gè)函數(shù) PyInit_foo() 。 然后你可以編寫 Python 代碼 “import foo” ,Python 將搜索 foo.pyd (以及 foo.py 、 foo.pyc )。如果找到它,將嘗試調(diào)用 PyInit_foo() 來初始化它。你不應(yīng)將 .exe 與 foo.lib 鏈接,因?yàn)檫@會(huì)導(dǎo)致 Windows 要求存在 DLL 。

請(qǐng)注意, foo.pyd 的搜索路徑是 PYTHONPATH ,與 Windows 用于搜索 foo.dll 的路徑不同。此外, foo.pyd 不需要存在來運(yùn)行你的程序,而如果你將程序與 dll 鏈接,則需要 dll 。 當(dāng)然,如果你想 import foo ,則需要 foo.pyd 。在 DLL 中,鏈接在源代碼中用 __declspec(dllexport) 聲明。 在 .pyd 中,鏈接在可用函數(shù)列表中定義。

我怎樣將 Python 嵌入一個(gè) Windows 程序??

在 Windows 應(yīng)用程序中嵌入 Python 解釋器可以總結(jié)如下:

  1. 請(qǐng) _不要_ 直接在你的 .exe 文件中內(nèi)置 Python 。在 Windows 上, Python 必須是一個(gè) DLL ,這樣才可以處理導(dǎo)入的本身就是 DLL 的模塊。(這是第一個(gè)未記錄的關(guān)鍵事實(shí)。)相反,鏈接到 pythonNN.dll ;它通常安裝在 C:\Windows\System 中。 NN 是 Python 版本,如數(shù)字“33”代表 Python 3.3 。

    你可以通過兩種不同的方式鏈接到 Python 。加載時(shí)鏈接意味著鏈接到 pythonNN.lib ,而運(yùn)行時(shí)鏈接意味著鏈接 pythonNN.dll 。(一般說明: python NN.lib 是所謂的“import lib”,對(duì)應(yīng)于 pythonNN.dll 。它只定義了鏈接器的符號(hào)。)

    運(yùn)行時(shí)鏈接極大地簡(jiǎn)化了鏈接選項(xiàng),一切都在運(yùn)行時(shí)發(fā)生。你的代碼必須使用 Windows 的 LoadLibraryEx() 程序加載 pythonNN.dll 。代碼還必須使用使用 Windows 的 GetProcAddress() 例程獲得的指針訪問 pythonNN.dll 中程序和數(shù)據(jù)(即 Python 的 C API )。宏可以使這些指針對(duì)任何調(diào)用 Python C API 中的例程的 C 代碼都是透明的。

  2. 如果你使用 SWIG ,很容易創(chuàng)建一個(gè) Python “擴(kuò)展模塊”,它將使應(yīng)用程序的數(shù)據(jù)和方法可供 Python 使用。SWIG將為你處理所有蹩腳的細(xì)節(jié)。結(jié)果是你將鏈接到 .exe 文件 的C代碼 (!) 你不必創(chuàng)建 DLL 文件,這也簡(jiǎn)化了鏈接。

  3. SWIG 將創(chuàng)建一個(gè) init 函數(shù)(一個(gè) C 函數(shù)),其名稱取決于擴(kuò)展模塊的名稱。例如,如果模塊的名稱是 leo ,則 init 函數(shù)將被稱為 initleo() 。 如果您使用 SWIG 陰影類,則 init 函數(shù)將被稱為 initleoc() 。這初始化了一個(gè)由陰影類使用的隱藏輔助類。

    你可以將步驟 2 中的 C 代碼鏈接到 .exe 文件的原因是調(diào)用初始化函數(shù)等同于將模塊導(dǎo)入 Python ! (這是第二個(gè)關(guān)鍵的未記載事實(shí)。)

  4. 簡(jiǎn)而言之,你可以用以下代碼使用擴(kuò)展模塊初始化 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 存在兩個(gè)問題,如果你使用除 MSVC 之外的編譯器用于構(gòu)建 python.dll ,這將會(huì)變得明顯。

    問題1:采用 FILE* 參數(shù)的所謂“極高級(jí)”函數(shù)在多編譯器環(huán)境中不起作用,因?yàn)槊總€(gè)編譯器的FILE結(jié)構(gòu)體概念都不同。從實(shí)現(xiàn)的角度來看,這些是非常 _低_ 級(jí)的功能。

    問題2:在為 void 函數(shù)生成包裝器時(shí),SWIG 會(huì)生成以下代碼:

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

    Py_None 是一個(gè)宏,它擴(kuò)展為對(duì) pythonNN.dll 中名為 _Py_NoneStruct 的復(fù)雜數(shù)據(jù)結(jié)構(gòu)的引用。同樣,此代碼將在多編譯器環(huán)境中失敗。將此類代碼替換為:

    return Py_BuildValue("");
    

    有可能使用 SWIG 的 %typemap 命令自動(dòng)進(jìn)行更改,但我無法使其工作(我是一個(gè)完全的SWIG新手)。

  6. 使用 Python shell 腳本從 Windows 應(yīng)用程序內(nèi)部建立 Python 解釋器窗口并不是一個(gè)好主意;生成的窗口將獨(dú)立于應(yīng)用程序的窗口系統(tǒng)。相反,你(或 wxPythonWindow 類)應(yīng)該創(chuàng)建一個(gè)“本機(jī)”解釋器窗口。將該窗口連接到Python解釋器很容易。你可以將 Python的 i/o 重定向到支持讀寫的 _任意_ 對(duì)象,因此你只需要一個(gè)包含 read() 和 write() 方法的 Python 對(duì)象(在擴(kuò)展模塊中定義)。

如何讓編輯器不要在我的 Python 源代碼中插入 tab ??

本 FAQ 不建議使用制表符, Python 樣式指南 PEP 8 ,為發(fā)行的 Python 代碼推薦 4 個(gè)空格;這也是 Emacs python-mode 默認(rèn)值。

在任何編輯器下,混合制表符和空格都是一個(gè)壞主意。 MSVC 在這方面沒有什么不同,并且很容易配置為使用空格: 點(diǎn)擊 Tools ? Options ? Tabs,對(duì)于文件類型“Default”,設(shè)置“Tab size”和“Indent size”為 4 ,并選擇“插入空格”單選按鈕。

如果混合制表符和空格導(dǎo)致前導(dǎo)空格出現(xiàn)問題, Python 會(huì)引發(fā) IndentationErrorTabError 。你還可以運(yùn)行 tabnanny 模塊以批處理模式檢查目錄樹。

如何在不阻塞的情況下檢查按鍵??

使用 msvcrt 模塊。 這是一個(gè)標(biāo)準(zhǔn)的 Windows 專屬擴(kuò)展模塊。 它定義了一個(gè)函數(shù) kbhit() 用于檢查是否有鍵盤中的某個(gè)鍵被按下,以及 getch() 用于獲取一個(gè)字符而不將其回顯。