有了 [pyenv](/ZJkqk8gYR7mEWXYsmp6mCw) 可以管理不同 Python 版本後, 搭配 [venv](/gOmzsLQRQtmyrpx8j8Z7iA) 建立虛擬環境雖然很不錯, 不過個別工具都要單獨使用, 如果有一個整合工具, 那就太方便了, 這就是 [pipenv](https://pipenv.pypa.io), 它把 [pip](https://pip.pypa.io/en/stable/)、[pyenv](https://github.com/pyenv/pyenv?tab=readme-ov-file#install-python-build-dependencies) 以及另一套虛擬環境管理工具 [virtualenv](https://virtualenv.pypa.io/en/latest/) 完美結合在一起, 而且跨平台, 可以讓你實現以單一資料夾為專案, 建立使用特定 Python 版本的虛擬環境, 再也不怕專案之間打架了。
## 安裝 pipenv
安裝 pipenv 只要使用 pip 即可, 但請記得安裝在你的使用者資料夾下, 避免它安裝的可執行檔因為移除 Python 而被刪除:
```shell!
# pip install --user pipenv
```
安裝完成後, 還要記得將安裝好的可執行檔所在的資料夾加入環境變數 PATH 中, 方便使用:
- 在 Windows 上可以透過以下指令查詢路徑:
```shell!
# python -m site --user-site
C:\Users\meebo\AppData\Roaming\Python\Python312\site-packages
```
這會找到 site-packages 資料夾的路徑, 剛剛安裝的可執行檔放置在上一層的 Scripts 下, 以剛剛的結果為例, 就要將 `C:\Users\meebo\AppData\Roaming\Python\Python312\Scripts` 加到 PATH 環境變數中。
- 在 Linux/macOS 上則可透過以下指令查詢路徑:
```shell
$ python -m site --user-base
/home/meebox/.local
```
安裝 pipenv 會將可執行檔放到這個路徑下的 bin 資料夾, 以剛剛的結果為例, 就要在 shell 的設定檔中將 `/home/meebox/.local/bin` 加到路徑中。
設定好環境變數後, 只要重新啟動 shell, 就可以使用 pipenv 了。
## 建立虛擬環境
要建立虛擬環境, 只要先建立專案資料夾, 切換到專案路徑後下達 `pipenv install` 指令即可。以下我們先使用 pyenv 指定使用 Python 3.12.1 版:
```shell!
# pyenv shell 3.12.1
# python
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
```
### 以最新安裝的 Python 版本建立虛擬環境
接著建立一個虛擬環境, 以下指令會以 pyenv 以安裝的最新 Python 版本 (3.12.1) 建立虛擬環境:
```shell
# mkdir test1
# cd test1
# pipenv install
Creating a Pipfile for this project...
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Locking [dev-packages] dependencies...
Updated Pipfile.lock (702ad05de9bc9de99a4807c8dde1686f31e0041d7b5f6f6b74861195a52110f5)!
Installing dependencies from Pipfile.lock (2110f5)...
To activate this project's virtualenv, run pipenv shell.
Alternatively, run a command inside the virtualenv with
pipenv run.
```
為了測試結果, 我們先將 Python 切換成不同版本:
```shell
# pyenv shell 3.11.7
# python
Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec 4 2023, 19:24:49) [MSC v.1937 64 bit (AMD64)] on win32
```
接著就可以在這個資料夾內以`pipenv run` 指令啟用虛擬環境執行程式, 例如:
```shell
# pipenv run python
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
```
你可以看到執行的是剛剛建立虛擬環境時使用的 3.12.1, 而不是現在的 3.11.7。如果覺得這樣執行程式有點麻煩, 也可以下達 `pipenv shell` 開啟啟用虛擬環境的 shell:
```shell
# pipenv shell
Launching subshell in virtual environment...
PowerShell 7.4.0
Loading personal and system profiles took 561ms.
# python
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
```
我們在這裡安裝 `cowsay` 套件, 稍後在其他專案資料夾建立虛擬環境時, 就可以看到虛擬環境的效果。
```shell
# pip install cowsay
Collecting cowsay
Downloading cowsay-6.1-py3-none-any.whl.metadata (5.6 kB)
Downloading cowsay-6.1-py3-none-any.whl (25 kB)
Installing collected packages: cowsay
Successfully installed cowsay-6.1
# pip list
Package Version
------- -------
cowsay 6.1
pip 23.3.2
# exit
```
安裝好之後使用 `exit` 指令離開這個 shell。
### 建立特定 Python 版本的虛擬環境
你也可以在建立虛擬環境時加入 `--python` 參數指定 Python 版本, 例如:
```shell
# cd ..
# mkdir test2
# cd test2
# pipenv install --python 3.12.1
Creating a virtualenv for this project...
Pipfile:
...
pipenv run.
```
這樣就在 test2 資料夾建立了一個同樣是 Python 3.12.1 版本的虛擬環境:
```shell
# pipenv run python
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec 7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
```
雖然都是 Python 3.12.1, 但因為會建立虛擬環境, 所以和之前的 test1 互相獨立, 你可以確認這個環境中並沒有剛剛安裝的 cowasay 套件:
```shell
# pipenv run pip list
Package Version
------- -------
pip 23.3.2
```
你可以看到這是一個乾淨的環境, 並沒有安裝任何套件。
### 以當前使用的 Python 版本建立虛擬環境
如果想要以目前 pyenv 採用的 Python 版本建立虛擬環境, 可以透過 `pyenv which python` 取得 Python 直譯器的完整路徑, `pipenv install` 的 `--python` 參數也可以接受路徑, 因此, 我們可以如下以當前 Python 版本建立虛擬環境:
```shell
# cd ..
# mkdir curr_version
# cd .\curr_version\
# pipenv install --python (pyenv which python)
Creating a virtualenv for this project...
Pipfile:
...
Alternatively, run a command inside the virtualenv with
pipenv run.
# pipenv run python
Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec 4 2023, 19:24:49) [MSC v.1937 64 bit (AMD64)] on win32
```
這樣就可以建立當前使用 Python 版本的虛擬環境, 而不用明確標示版本了。
### 建立虛擬環境同時安裝特定的 Python 版本
由於 pipenv 與 pyenv 緊密結合, 所以如果建立虛擬環境時指定的 Python 版本尚未安裝, 它也可以透過 pyenv 自動安裝, 例如:
```shell
# cd ..
# mkdir test3
# cd test3
# pipenv install --python 3.10.8
Warning: Python 3.10.8 was not found on your system...
Would you like us to install CPython 3.10.8 with Pyenv? [Y/n]:
```
當 pipenv 發現指定的 Python 3.10.8 尚未安裝時, 就會問我們是否要安裝這個版本。按下 Y 就會開始安裝並在安裝完成後建立虛擬環境, 我們可以確認看看是否會執行 3.10.8 版:
```shell
# pipenv run python
Python 3.10.8 (tags/v3.10.8:aaaf517, Oct 11 2022, 16:50:30) [MSC v.1933 64 bit (AMD64)] on win32
```
透過這樣的方式, 就可以以資料夾為單位建立專案, 並且以指定的 Python 版本建立虛擬環境, 非常方便。
### 以非 pyenv 安裝的 python 版本建立虛擬環境
雖然 pipenv 和 pyenv 是絕配, 不過如果你的系統上有不是透過 pyenv 安裝的 Python, 只要在 PATH 環境變數的路徑中可以找到, 或是直接指定路徑, 也一樣可以使用 pipenv 建立虛擬環境。
例如系統上有透過官網下載安裝的 3.9.6 版:
```shell
# py -0p
-V:3.9 * C:\Users\meebo\AppData\Local\Programs\Python\Python39\python.exe
# py -3.9 -V
Python 3.9.6
```
如果將所在路徑加入 PATH 中:
```shell
# $env:PATH = $env:path+'C:\Users\meebo\AppData\Local\Programs\Python\Python39'
# mkdir testPY
```
就可以建立虛擬環境:
```shell
# cd testPY
# pipenv install --python 3.9.6
Creating a virtualenv for this project...
Pipfile: C:\Users\meebo\code\python\testPY\Pipfile
Using c:/users/meebo/appdata/local/programs/python/python39/python.exe (3.9.6) to create virtualenv...
[====] Creating virtual environment...created virtual environment CPython3.9.6.final.0-64 in 871ms
...
# pipenv run python
Python 3.9.6 (tags/v3.9.6:db3ff76, Jun 28 2021, 15:26:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
你也可以在建立虛擬環境時直接指定 python 執行檔的路徑:
```shell
# cd ..
# mkdir testPATH
# cd .\testPATH\
# pipenv install --python C:\Users\meebo\AppData\Local\Programs\Python\Python39\python.exe
Creating a virtualenv for this project...
Pipfile: C:\Users\meebo\code\python\testPATH\Pipfile
Using C:\Users\meebo\AppData\Local\Programs\Python\Python39\python.exe (3.9.6) to create virtualenv...
[ ===] Creating virtual environment...created virtual environment CPython3.9.6.final.0-64 in 826ms
...
```
不過我還是建議讓 pipenv 搭配 pyenv 使用會比較簡單。
## 安裝套件
要在虛擬環境中安裝套件, 可以直接透過 `pipenv install` 指令, 或者也可以 `pipenv shell` 啟用虛擬環境開啟 shell 後, 在 shell 中以 pip 指令逕行安裝。以下我們就幫剛剛建立的虛擬環境安裝 coesay 套件:
```shell
# pipenv install cowsay
Installing cowsay...
Resolving cowsay...
...
pipenv run.
```
## 專案資料夾的異動
建立好專案的虛擬環境後, 如果專案資料夾要異動, 都有需要注意的地方。
### 複製專案資料夾
如果你想要將已經建立的專案資料夾複製到其他地方使用, 只要在複製後重新執行 `pipenv install` 指令即可, 例如:
```shell
# cd ..
# cp -r test3 test4
# cd test4
# pipenv install
Creating a virtualenv for this project...
Pipfile:
...
pipenv run.
# pipenv run python
Python 3.10.8 (tags/v3.10.8:aaaf517, Oct 11 2022, 16:50:30) [MSC v.1933 64 bit (AMD64)] on win32
```
這樣就可以複製出一個相同版本的虛擬環境, 而且也會自動安裝原來虛擬環境中的套件:
```shell
# pipenv run pip list
Package Version
---------- -------
cowsay 6.1
pip 23.3.2
setuptools 69.0.3
wheel 0.42.0
```
其實你也可以在複製資料夾後, 直接以 `pipenv run` 或是 `pipenv shell` 指令執行, pipenv 會在發現這個專案資料夾還沒有建立虛擬環境時自動建立。
### 搬移專案資料夾
如果是要將專案搬移位置, 基本程序就和複製專案資料夾一樣, 不過由於虛擬環境的資料是儲存在其他位置, 最好在搬移前先移除虛擬環境, 否則搬移到新位置重新建立虛擬環境後, 原來的虛擬環境就變成孤兒, 徒然浪費儲存空間。
例如, 若要將 test4 改名為 test5, 就可以先使用 `pipenv --rm` 指令刪除虛擬環境之後再搬移, 重新建立虛擬環境:
```shell
# pipenv --rm
Removing virtualenv
(C:\Users\meebo\.virtualenvs\test4-JuXU8pfP)...
# cd ..
# mv test4 test5
# cd test5
# pipenv install
Creating a virtualenv for this project...
Pipfile:
...
# pipenv run pip list
Package Version
---------- -------
cowsay 6.1
pip 23.3.2
setuptools 69.0.3
wheel 0.42.0
```
### 刪除專案
由於 pipenv 是以資料夾為專案, 所以若是要刪除專案, 其實就是把資料夾移除即可。不過和搬移專案資料夾一樣, 最好在刪除專案資料夾之前先使用 `pipenv --rm` 移除虛擬環境的資料, 避免佔用儲存空間。
## pipenv 的紀錄檔
你可能會覺得有點神奇, 移除虛擬環境的資料後, 為什麼可以重新建立一模一樣的虛擬環境?這主要是因為 pipenv 會將相關資訊記錄在資料夾中的 Pipfile 檔:
```shell
# cat .\Pipfile
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
cowsay = "*"
[dev-packages]
[requires]
python_version = "3.10"
python_full_version = "3.10.8"
```
你可以看到這個檔案中記錄了要使用的 Python 版本以及安裝的套件。當 pipenv 發現這個資料夾還沒有建立虛擬環境時, 就會依據檔案內容建立虛擬環境, 並且安裝所有的套件。
## 查看虛擬環境的儲存路徑
如果想要知道專案對應的虛擬環境儲存在哪裡, 可以下達 `pipenv --venv` 指令:
```shell
# pipenv --venv
C:\Users\meebo\.virtualenvs\test5-fZIsUw1B
# ls C:\Users\meebo\.virtualenvs\test5-fZIsUw1B
Directory: C:\Users\meebo\.virtualenvs\test5-fZIsUw1B
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2024/1/8 下午 10:15 Lib
d---- 2024/1/8 下午 10:15 Scripts
d---- 2024/1/8 下午 10:15 src
-a--- 2024/1/8 下午 10:15 42 .gitignore
-a--- 2024/1/8 下午 10:15 32 .project
-a--- 2024/1/8 下午 10:15 399 pyvenv.cfg
```
你可以看到實際上虛擬環境的資料都是儲存在這裡, 如果你搬移專案或是刪除專案時沒有移除虛擬環境, 而且又安裝了一大堆的套件, 就會佔用非常多的儲存空間。
另外, 要特別提醒的是, 虛擬環境的名稱預設是以專案資料夾的完整路徑編碼而成, 如果你移除或是搬移專案時沒有先移除虛擬環境, 日後若在同一位置建立相同名稱的專案資料夾, 就會沿用殘留的虛擬環境, 造成不必要的問題。舉例來說, 假設剛剛建立的 test5 專案已經結束, 所以我們把資料夾刪除, 同時也把不再需要的 Python 3.10.8 移除:
```shell
# cd ..
# rm -r -Force test5
# pyenv uninstall 3.10.8
pyenv: Successfully uninstalled 3.10.8
```
由於我們沒有移除虛擬環境, 所以如果在同樣位置再次建立 test5 資料夾:
```shell
# mkdir test5
# cd test5
```
再重新進入資料夾建立虛擬環境:
```shell
# pipenv install
Creating a Pipfile for this project...
...
Alternatively, run a command inside the virtualenv with
pipenv run.
# pipenv run python
No Python at '"c:\users\meebo\.pyenv\pyenv-win\versions\3.10.8\python.exe'
```
你可以看到沒有指定版本建立虛擬環境時, 應該會以 pyenv 以安裝的最新版本 3.12.1 為依據建立全新的虛擬環境。但是當你啟用虛擬環境執行時, 會發現它想要執行的是殘留的虛擬環境設定的 3.10.8 版。
即使你指定安裝版本也沒用:
```shell
# pipenv install --python 3.12.1
Creating a Pipfile for this project...
...
Alternatively, run a command inside the virtualenv with
pipenv run.
# pipenv run python
No Python at '"c:\users\meebo\.pyenv\pyenv-win\versions\3.10.8\python.exe'
```
也正因為如此, 才會不斷強調要搬移或是移除專案前, 最好先移除虛擬環境, 這樣既不會佔用空間, 也不會造成意外的結果。