製作可攜版Python

Python的安裝非常簡單與便利,但有時候我們仍然需要一個可以隨身帶著走的Python環境,讓我們得以不透過將程式打包成執行檔等方式,快速有一個執行與使用的環境。

Jerome Lin
Coding Learning Sharing
Oct 23, 2022

--

前言

說是可攜版,其實就是使用Python的嵌入式版本,簡單來說,這樣的嵌入式版本,可以讓我們把特定一個版本號的Python執行環境帶到一個合適(相容)的作業系統當中。基本上如此做的目的或好處是,我們可以與某個(些)會取用到Python的應用程式一起安裝(安裝該應用程式時,直接將Python的嵌入式版本給解壓縮出來,放到適當的位置)或者直接使用(此應用程式本身也是可攜版的情況下),而不必另外去取得某個相容版本的Python,並重新安裝它。這聽起來應該是很不錯的,因為這也方便控管該版本的應用程式本身附帶的Python,其版本是相容的,避免使用者安裝錯誤導致非預期問題發生。

使用環境

作業系統: Windows 10 64-bit

Python版本: 3.10.7 64-bit

取得Python嵌入式版本

我們可以先到Python官方網站去下載各種版本的Python,如以下連結:

通常在某個release版本下,我們可以看到如以下畫面:

一般而言,可以選擇installer的版本,畢竟會有安裝程式的GUI視窗引導。但這邊選擇embeddable package。當然,想要選擇32位元或者64位元,就依據自己的情況去下載。

打開下載下來的壓縮檔,可以看到其內容物很簡單,基本上也沒有子目錄:

這次會動用到的東西基本上,是上圖中的紅框所框起來的檔案,其中,我們可以看到python.exe,這是平常我們呼叫Python執行指令或者py檔的來源檔案。此外,還有看到pythonw.exe,這是一個忽略console視窗的執行檔,執行時不會有console視窗跑出來,與之對應的是pyw副檔名的檔案(如下圖所示),這可以用來做一些有趣,背景運行的東西。

而整個壓縮檔裡面,還有放置一個python310.zip的壓縮檔,裡面主要存放著經過Compile的內建函式庫,以bytecode形式呈現(pyc檔),除了這個之外,當然也還是會有一些額外的東西。

取得pip

我們可以注意到,裡面其實不含pip套件管理程式的,假設需要一些使用到第三方套件,不管是在可攜式環境或者純粹用作測試、暫時性的用途,可能就有點綁手腳。當然,我們也可以自己把pip整合進這個嵌入式版本裡面。

為了讓安裝pip的過程更簡便,我們是可以透過腳本來進行安裝的:

主要我們需要取得get-pip.py檔案,並透過這個腳本來自動化pip的安裝過程:

https://bootstrap.pypa.io/get-pip.py

下載好get-pip.py後,我們將其放進解壓縮後的python資料夾中:

因為這個腳本本身就是個Python程式碼,我們只要透過以下指令執行該目錄下的get-pip.py即可。

python get-pip.py

執行過程如下圖所示:

這個安裝過程是沒有主動添加環境變數的,這也符合我們想要達到可攜式的目的。

安裝後基本會出現兩個資料夾,如下圖所示:

pip.exe(or pip3.exe)便在Scripts資料夾當中。

這邊要特別注意到,pip的安裝會綁死當前路徑,所以擅自將pip檔案移動到其他地方,除非特地自己去修改成適當的路徑,不然執行是會有問題的。所以如果是有執行pip的需求,基本上是額外進行的,無法一起打包。

確實到目前這步,pip的安裝就完成了,但如果這個時候,就想使用pip,可能會出現以下錯誤訊息:

錯誤訊息提示說找不到pip模組,這是因為適當的路徑設定並沒有載入成功,為了可以讀取到pip模組,需要修改python310._pth(若是使用其他版本則依版本號為主),取消註解import site這行。

為了知道有無import site這行的差異,我們可以透過以下指令確認路徑有哪些改變。

python -c "import sys; print(sys.path);"

取消註解前:

取消註解後:

可以看到import site,有一個作用是找到Path\to\Lib\site-packages並將其加入到模組搜尋路徑中。

此外,也可以觀察到其他兩個路徑則是對應到python310._pth的前兩行所指定的位置。

我們還可以做個測試,如果將python310._pth當中的每一行都註解,則會出現以下錯誤訊息:

除了設定好載入路徑之外,我們還可能需要在根目錄中手動添加一個DLLs資料夾,這個是為了避免執行過程中找不到這個資料夾位置。

總而言之,我們現在應該可以執行pip了。

解壓縮python310.zip

前面也有提到python310.zip,裡面有許多資料夾以及檔案,其中就有包含pickle檔,比如Path\to\python310.zip\lib2to3\Grammar3.10.4.final.0.pickle

而基本上,python使用內建功能在解析pickle檔時,會無法正常讀取壓縮檔當中的pickle檔(除非修改成解析前先進行解壓縮再讀取pickle檔),所以這邊為了方便,才需要事先手動解壓縮python310.zip,解壓縮後的資料夾名稱也要是python310.zip(為了避免名稱相同而衝突,需要先刪除原本的python310.zip壓縮檔或者改變其名稱,這是因為在Windows當中,檔案含副檔名的名稱與資料夾名稱也不能相同)。

而為何一定要python310.zip這個名字,當然是因為前面的python310._pth就是這樣設定。

最後的目錄結構大致上如下圖所示:

移動已安裝好的pip會發生的狀況

前面我們有提到,安裝好的pip其實是會綁死安裝路徑的(寫在pip.exe檔中),所以移動pip之後,除非原本安裝路徑的pip.exe仍存在,不然執行是會出錯的。如下圖所示:

前後兩個pip -V,兩個的差別在於前者是在原本的pip.exe仍存在在原先安裝的路徑上執行的結果,可以看到雖然pip.exe被複製到其他地方後(所以原本的pip.exe仍存在),仍綁定在舊路徑。

下圖為使用文字編輯器打開查看,可以看到路徑如何被綁定:

結論

本篇主要是介紹如何製作自己的可攜式Python環境,比起直接透過installer安裝,麻煩了許多,也有一些細節要特別注意,往後的執行才不會出錯。若是單純作為一個穩定版本、嵌入、可攜式用途,基本上pip就不需要特別打包在一起。

不過如果是想要把已經製作好且包含pip的可攜版Python複製或移動出來到其他地方,為了讓pip可以使用,第一可以修改在相關檔案所綁定的路徑,第二當然是寫個腳本去自動安裝pip,如此可以透過點擊就能直接安裝,也可以自行添加一些其他的功能,做環境的預處理。

--

--

Jerome Lin
Coding Learning Sharing

覺得平凡就好,但還是多少充實一下人生。It feels good to be ordinary, but you still need to enrich your life a little bit. Buy Me A Coffee: https://www.buymeacoffee.com/jeromelinil