Python 的虛擬環境(Virtual Environment)是一個獨立的資料夾結構,用來管理程式專案內的套件相依性。光是這樣以定義介紹想必不夠直觀,我們直接看一個需要虛擬環境來救援的實戰範例:
我曾經在回顧公司內的某份分析報告,它用到的其中一個 Python pandas
程式碼片段類似以下範例,邏輯簡單、但它卻出現 bug:
import pandas as pd
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
result_df = df1.append(df2, ignore_index=True)
print(result_df)
Bug 的錯誤訊息:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-1-db924093590a> in <cell line: 6>()
4 df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
5
----> 6 result_df = df1.append(df2, ignore_index=True)
(... 部分省略 ...)
AttributeError: 'DataFrame' object has no attribute 'append'
明明是其他人完整跑過的程式碼、怎麼會出現「查無此 append
函式」這種 bug 呢?!問題在於 pandas
套件不再支援這個函式了!在特定套件版本以後,不能再使用 append
、相似功能必須改用 concat
。
為了讓你寫好的 Python 程式,不會因為其他套件更動、而在未來的某一天突然跑不動
我們需要虛擬環境 Virtual Environment 來避免這個問題!
Python 虛擬環境是開發者必備的工具之一,它能有效隔離不同專案的套件相依性、避免衝突、並確保每個專案的穩定性,而筆者作為資料科學家,非常依賴虛擬環境讓我的分析保持再現性。本文將深入淺出地介紹 Python 虛擬環境的概念、重要性,以及如何使用常見的工具 venv
來建立和管理虛擬環境。我相信無論你是初學者還是經驗豐富的開發者,這則學習筆記都能讓你有收穫。
目錄
什麼是虛擬環境 Virtual Environment?
Python 虛擬環境(Virtual Environment)是一個獨立的 Python 環境,與系統中其他 Python 環境隔離。它可以幫助您管理不同專案所需的套件版本,避免衝突和相依性問題。想像一下,你的電腦上有多個 Python 專案,每個專案可能需要不同版本的套件。如果將所有專案的套件都安裝在系統的 Python 環境中,很容易發生衝突,導致某些專案無法正常運作。
如果沒有使用虛擬環境,電腦預設只會有唯一一個系統的 Python 全域環境(Global Environment),既然只有一個環境、你安裝的套件也只會存在唯一一個版本。用前言提到 pandas
舉例,每次你使用 pip3 install --upgrade pandas
來更新套件後,都有可能影響到你以前寫好的分析程式,狀況會像是:
- 你最近一次更新
pandas
後,套件版本是 2.2.2 - 你好幾年前寫的專案用到
pandas
,當時使用套件版本 1.0.0 - 你前兩個月寫的專案也用到
pandas
,當時使用套件版本是 2.0.1 - 等等
你以前寫程式當時使用的套件版本,跟你目前全域環境安裝的最新套件版本,很有可能不同,若是發生如前言所述「舊版本套件的某些功能在新版不再支援」、或是「新舊版套件的某些功能運作方式不同」,都有可能造成你以前寫好的程式出現額外的 bug、再也不能正常運作。
虛擬環境就像是獨立的房間,每個房間都有自己的 Python 版本和套件。當你切換到不同的虛擬環境時,您就像在不同的房間中,使用不同的工具和資源。這樣,每個專案都能擁有它所需的環境,而不會影響其他專案。
虛擬環境怎麼運作?
若要我過度簡化地介紹虛擬環境到底做了什麼,我會說:
虛擬環境基本上就是幫你的專案開個資料夾 (˚∀˚)
建立一個虛擬環境時,系統會在電腦上建立一個獨立的資料夾,這個資料夾包含了 Python 直譯器、標準函式庫、以及其他必要的檔案,這個資料夾就是你專案的虛擬環境。
當你在指定的虛擬環境中安裝套件時,這些套件會被安裝到該虛擬環境對應的資料夾中,而不是系統的全域 Python 環境。這樣,每個虛擬環境都有自己獨立的套件安裝資料夾,每個專案各用各的套件版本、就不會起衝突!
虛擬環境還涉及路徑(sys.path
)管理。當我們在虛擬環境中執行 Python 程式時,Python 直譯器會優先搜尋虛擬環境的套件資料夾,而不是系統的全域套件資料夾,更細節地說,你要 import
某套件時,Python 會先搜尋虛擬環境資料夾中有沒有指定的、安裝好的套件版本,如果沒有,才回到系統的全域 Python 環境去找套件。這確保了我們在虛擬環境中使用的套件版本是正確的(符合我們寫程式當下指定的)。
為什麼需要虛擬環境?
使用虛擬環境是開發的好習慣,確保專案之間獨立互不衝突、程式行為穩定一致。
每一個 Python 專案都可以有自己的獨立虛擬環境。這意味著,每個專案可以使用不同的 Python 版本和套件,而不會影響其他專案。例如,一個網頁爬蟲專案(web crawler)會用到一堆套件,經常包括 requests
、BeautifulSoup
、Scrapy
等等,爬蟲寫好的當下、用的都是這些套件的特定版本與對應功能,而每個爬蟲專案用到的套件版本可能不同。這狀況聽起來一團亂,只要使用虛擬環境,就可以輕鬆地管理這些套件版本差異,避免衝突和相依性問題。
筆者好豪作為資料科學家,更是依賴虛擬環境來維持 Python 程式穩定性和一致性。虛擬環境確保了專案在不同的環境與時空背景中都能正常運作。無論是在本地開發、部署到雲端伺服器,還是與其他同事合作,虛擬環境都能提供一致的執行環境,有助於減少因為環境改變(而不是程式本身)產生的錯誤、提高開發效率。
數據分析工作整天都在「算數字」,有虛擬環境才能保證這些數字未來、或是交給同事之後還能不出錯地算出來,更重要的是能得到一模一樣的數字結果。對於統計分析而言,再現性(Reproducibility)至關重要,如果你對再現性的概念還不熟悉,強烈推薦你推薦這篇簡短的學術文章:《十個讓研究符合再現性的簡單原則》,該作者提到的第三條原則「管理好統計軟體的版本」正是本文的虛擬環境能解決的痛點。
Python 的 venv
使用教學
到這個小節,我們終於開始動手寫程式學習使用 Python 虛擬環境。對於 Python 或是使用虛擬環境的新手,venv
套件 是最推薦的入門款:
- 預先安裝在 Python 本體中:從 Python 3.3 版本開始,
venv
已被加入 Python 標準函式庫之中,不用另外用 pip 安裝 - 官方推薦:點進 文件 就能看到,從 Python 3.5 版本開始,Python 官方開發者「建議使用
venv
來建立虛擬環境」 - 功能簡約:直觀、簡單是
venv
最大的優點之一,專注在最基礎的功能,包括創造、啟用、管理虛擬環境。這些基本功能已足以發揮虛擬環境的威力 - 輕量且高效:
venv
會在必要時引用 Python 的內建模組,不會真的複製一大堆重複性很高的檔案到你開的虛擬環境資料夾,十分有效率
那我們開始學習使用 venv
吧。
建立虛擬環境
首先是使用終端機(Command Line / Terminal)建立虛擬環境:
$ python -m venv my_env
python -m
:用 Python 執行指定模組(module)的程式- 部分電腦可能需要用
python3 -m
才能執行
- 部分電腦可能需要用
venv
:承上,venv
正是我們指定要執行的模組 / 套件my_env
:新建立的虛擬環境名稱
由於虛擬環境實際上是在開個資料夾,my_env
會是新的資料夾名稱,當然,執行以上指令不是開資料夾那麼簡單,這個新資料夾內同時會建立一些虛擬環境的必要檔案還有子資料夾結構。
啟用虛擬環境
建立虛擬環境後,我們得先啟用(activate)虛擬環境,才能接著進行我們的重要工作,像是安裝套件等等。
在 Mac / Linux 啟用虛擬環境的方法:
$ source my_env/bin/activate
Windows 的做法則是:
$ my_env\Scripts\activate
啟用後,你的終端機命令列會顯示出你所在的虛擬環境名稱(my_env
),讓你明顯看得出來自己正在虛擬環境內工作。
啟用虛擬環境代表系統環境變數(PATH
)會被改變,當你在虛擬環境內部執行 python
相關指令時,屬於你指定虛擬環境的 Python 直譯器與套件會被優先執行。
套件管理
啟用虛擬環境後,你就可以用 pip
(或 pip3
)來安裝、更新、或著移除套件,而且是只限在你當下的指定虛擬環境之中。以下程式碼用一個叫 rich
的套件示範,我的全域環境跟虛擬環境都沒有這個套件:
# 我的 Python 全域環境並沒有 rich 套件
$ python -m rich
/usr/local/opt/[email protected]/bin/python3.9: No module named rich
# 啟用虛擬環境 my_env
$ source my_env/bin/activate
# 虛擬環境 my_env 內也沒有這個 rich 套件
(my_env) $ python -m rich
/Users/HaoSquare/my_env/bin/python3: No module named rich
# 在虛擬環境內,安裝 rich 套件
(my_env) $ pip install rich
Collecting rich
Downloading rich-13.9.4-py3-none-any.whl (242 kB)
|████████████████████████████████| 242 kB 1.4 MB/s
(... 輸出內容省略 ...)
Successfully installed markdown-it-py-3.0.0 mdurl-0.1.2 pygments-2.18.0 rich-13.9.4 typing-extensions-4.12.2
# 虛擬環境內安裝完成、也確實可執行 rich 套件
(my_env) $ python -m rich
Rich features
Colors ✓ 4-bit color ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
✓ 8-bit color ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
✓ Truecolor (16.7 million) ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
(... 輸出內容省略 ...)
# 離開 my_env 虛擬環境
(my_env) $ deactivate
# 再次嘗試,Python 全域環境依然 *無法* 執行 rich 套件
# 表示虛擬環境內「安裝 rich 套件」的行為,並 *不會* 影響到任何其他的環境
# 這就是虛擬環境的優點!
$ python -m rich
/usr/local/opt/[email protected]/bin/python3.9: No module named rich
任何你在此用 pip
安裝或更新的套件,都只限於這個虛擬環境的資料夾之中,具體而言,套件都會在 site-packages
這個子資料夾內被管理。
離開虛擬環境
在當下的虛擬環境工作完畢,想要離開(deactivate)此虛擬環境,動作非常簡單:
(my_env) $ deactivate
執行此指令後,不只離開虛擬環境,前面 activate 動作造成的系統環境變數(PATH
)改變,都會被恢復原狀。
刪除虛擬環境
虛擬環境的本體是個資料夾,所以要刪除虛擬環境也很簡單,你可以用滑鼠右鍵、直接把該資料夾丟進資源回收桶,或者用命令列:
$ rm -rf my_env
千萬記得:刪除虛擬環境之前,要先離開(deactivate)虛擬環境。
venv
整合範例:不會「算不出來」的 pandas
數據分析
學會 venv
操作後,我們用前言的 pandas
bug 來整理一下:如何確保我現在的數據分析,未來能夠再現(Reproducible)、能無錯誤地得出相同數字結果?
假設前言的 pandas
程式碼被放在 pd_example.py
檔案內,而且過去分析時,是使用 pandas
的 1.2.1 版本,而且 numpy
版本是 1.26.4:
# pd_example.py
import pandas as pd
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
result_df = df1.append(df2, ignore_index=True)
print(result_df)
我們再看一次全域環境執行此程式的問題點:
# 全域環境執行,bug 訊息說查無此函式!
$ python pd_example.py
Traceback (most recent call last):
File "/Users/HaoSquare/pd_example.py", line 8, in <module>
(... 部分省略 ...)
AttributeError: 'DataFrame' object has no attribute 'append'
# 檢視我在全域環境的 pandas 版本
# 看到 pandas 是 2.2.3 版本
# 與以上分析程式所要求的 pandas 版本(1.2.1)不符
$ python -m pip freeze
appdirs==1.4.4
astroid==2.8.4
audioread==2.1.9
(... 部分省略 ...)
numpy==2.0.2
packaging==20.9
pandas==2.2.3
(... 以下省略 ...)
我們運用虛擬環境,在不影響任何其他環境的前提下、明確控管 pandas
套件版本:
# 創建虛擬環境
$ python -m venv my_pd_analysis
# 啟用虛擬環境 my_pd_analysis
$ source my_pd_analysis/bin/activate
# 在虛擬環境內安裝 *指定版本* 的 pandas 與 numpy 套件
(my_pd_analysis) $ pip install pandas==1.2.1
Collecting pandas==1.2.1
Downloading pandas-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl (10.7 MB)
|████████████████████████████████| 10.7 MB 49 kB/s
(... 部分省略 ...)
Successfully installed numpy-2.0.2 pandas-1.2.1 python-dateutil-2.9.0.post0 pytz-2024.2 six-1.16.0
(my_pd_analysis) $ pip install numpy==1.26.4
Collecting numpy==1.26.4
Downloading numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl (20.6 MB)
|████████████████████████████████| 20.6 MB 49 kB/s
(... 部分省略 ...)
Successfully installed numpy-1.26.4
# 使用指定版本的套件後,分析程式終於又能順利執行了!
(my_pd_analysis) $ python pd_example.py
A B
0 1 3
1 2 4
2 5 7
3 6 8
# 離開虛擬環境
(my_pd_analysis) $ deactivate
離開虛擬環境後可以再次確認,我們在 my_pd_analysis
虛擬環境內部更改的任何套件版本,都不會影響全域環境:
# 再次檢視我在全域環境的 pandas 與 numpy 版本
# 沒有任何變化
$ python -m pip freeze
appdirs==1.4.4
astroid==2.8.4
audioread==2.1.9
(... 部分省略 ...)
numpy==2.0.2
packaging==20.9
pandas==2.2.3
(... 以下省略 ...)
寫到這裡,我們整理出資料科學要達成再現性的最佳做法:執行任何數據分析專案時,不只要存下程式碼,還要建立並保存虛擬環境的資料夾,才能確保未來回顧這項分析時,資料整理與統計分析的套件都是使用一模一樣的版本,算出來的數字也才能夠一模一樣!
更多(容易搞混的)虛擬環境套件
虛擬環境還有更多值得探索的功能!但我承認我大多數時候只用了 venv
,如果你對更多相關虛擬環境與套件管理工具有興趣,我在這裡列出一些我研究過的常見選項,供你參考:
虛擬環境建立:
venv
:Python3 的官方推薦virtualenv
:基本功能跟venv
一樣,所以擇一即可。比venv
彈性更高、多了一些進階功能- 可參考官方文件的 兩者比較
pyvenv
:Python 3.8 版本後已被移除,不建議再使用
要管理 Python 版本(注意,不是管理套件版本)的時候,則可以使用 pyenv
。例如,你寫的程式需要在 Python 的 2.7、3.6、3.12 等多個版本測試、需要經常切換,這就是需要 pyenv
的情境。
讓工作流更方便的工具:
virtualenvwrapper
:是virtualenv
的延伸,主要特色是中央管理多個虛擬環境,而不是讓虛擬環境資料夾散落在不同位置pyenv-virtualenvwrapper
:要是你需要同時使用virtualenvwrapper
與pyenv
,這個套件讓你工作更加方便pipenv
:結合pip
與virtualenv
的功能
依照使用情境選擇適合工具
那麼多工具看了一頭霧水嗎?我也是學得很頭痛!尤其 pyvenv
、pyenv
、pipenv
這種名字長很像的,真的很容易搞錯。所以,我覺得透過使用情境來選擇工具、而不用死記硬背每個工具的功能,會更有效率:
- 當你使用 Python3,想要用虛擬環境管理多個套件版本:用標準函式庫的
venv
- 同上,但是你會用到 Python2:使用
virtualenv
- 你需要切換不同 Python 版本:管理 Python 版本用
pyenv
,管理套件版本用virtualenv
- 你的專案很多,需要很多虛擬環境,包括多個 Python 版本或套件版本:
pyenv
+virtualenvwrapper
或者直接用pyenv-virtualenvwrapper
額外補充:
conda
:可以想成pip
+virtualenv
的集大成,還能跨平台(Windows、Linux、OS X),再加上支援多個語言,除了 Python 還有 R、Julia 等等,資料科學家經常優先使用conda
來替代pip
與 `virtualenvmamba
:與conda
極相似,但經過 C++ 改寫、執行速度比conda
高uv
:2024 年爆紅的新星,號稱只用此套件就能替代pip
+pyenv
+virtualenv
等所有工具,執行速度還比上述套件都快超多,也有許多人認為uv
會替代conda
的地位- 我會說,只要你常用到
pip
、pyenv
、virtualenv
、venv
其中至少一個套件,那就值得試試uv
套件
- 我會說,只要你常用到
結語
我記得我剛開始學 Python 程式不到一年的時候,看到虛擬環境關鍵字就覺得好複雜、好難懂,但其實邊學程式、邊實際工作的過程中,確實遇到超多使用情境,如果熟悉虛擬環境的運作,真的會幫自己跟團隊都省掉很多麻煩,像是:
- 引用多個統計分析套件的資料科學專案
- 依賴特定前後端框架版本的網頁開發
- 使用到不同演算法套件的機器學習實驗
- 多個 Python 與套件版本組合的軟體測試
- 等等
所以現在,我會盡力做到最佳實踐(Best Practice)、讓虛擬環境融入我每個專案的工作流:
- 每個開發或數據分析專案都創立獨立的虛擬環境
- 用虛擬環境資料夾有條理地整理專案
- 各個專案清晰列出依賴的 Python 與套件版本
我相信你讀完這篇文章後,已經了解 Python 的虛擬環境怎麼運作、為什麼虛擬環境重要,也學會怎麼動手運用。若你還沒使用過虛擬環境,你的下一個程式開發專案,請務必使用 venv
,讓你的程式更整潔且穩健。
參考資料:
你也正在努力自學 Python 嗎?我整理了 Python 實用自學資源,推薦熱愛自學程式的你繼續閱讀!如果這篇文章有幫助到你,也歡迎追蹤好豪的 Facebook 粉絲專頁 以及 Threads 帳號,我會持續分享 Python 相關知識;也歡迎點選下方按鈕將本文加入書籤、或者分享給更多正在學 Python 的朋友。