Try   HackMD

有了 pyenv 可以管理不同 Python 版本後, 搭配 venv 建立虛擬環境雖然很不錯, 不過個別工具都要單獨使用, 如果有一個整合工具, 那就太方便了, 這就是 pipenv, 它把 pippyenv 以及另一套虛擬環境管理工具 virtualenv 完美結合在一起, 而且跨平台, 可以讓你實現以單一資料夾為專案, 建立使用特定 Python 版本的虛擬環境, 再也不怕專案之間打架了。

安裝 pipenv

安裝 pipenv 只要使用 pip 即可, 但請記得安裝在你的使用者資料夾下, 避免它安裝的可執行檔因為移除 Python 而被刪除:

# pip install --user pipenv

安裝完成後, 還要記得將安裝好的可執行檔所在的資料夾加入環境變數 PATH 中, 方便使用:

  • 在 Windows 上可以透過以下指令查詢路徑:

    ​​​​# 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 上則可透過以下指令查詢路徑:

    ​​​​$ python -m site --user-base
    ​​​​/home/meebox/.local
    

    安裝 pipenv 會將可執行檔放到這個路徑下的 bin 資料夾, 以剛剛的結果為例, 就要在 shell 的設定檔中將 /home/meebox/.local/bin 加到路徑中。

設定好環境變數後, 只要重新啟動 shell, 就可以使用 pipenv 了。

建立虛擬環境

要建立虛擬環境, 只要先建立專案資料夾, 切換到專案路徑後下達 pipenv install 指令即可。以下我們先使用 pyenv 指定使用 Python 3.12.1 版:

# 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) 建立虛擬環境:

# 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 切換成不同版本:

# 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 指令啟用虛擬環境執行程式, 例如:

# 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:

# 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 套件, 稍後在其他專案資料夾建立虛擬環境時, 就可以看到虛擬環境的效果。

# 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 版本, 例如:

# 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 版本的虛擬環境:

# 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 套件:

# pipenv run pip list
Package Version
------- -------
pip     23.3.2

你可以看到這是一個乾淨的環境, 並沒有安裝任何套件。

以當前使用的 Python 版本建立虛擬環境

如果想要以目前 pyenv 採用的 Python 版本建立虛擬環境, 可以透過 pyenv which python 取得 Python 直譯器的完整路徑, pipenv install--python 參數也可以接受路徑, 因此, 我們可以如下以當前 Python 版本建立虛擬環境:

# 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 自動安裝, 例如:

# 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 版:

# 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 版:

# py -0p
 -V:3.9 *         C:\Users\meebo\AppData\Local\Programs\Python\Python39\python.exe
# py -3.9 -V
Python 3.9.6

如果將所在路徑加入 PATH 中:

# $env:PATH = $env:path+'C:\Users\meebo\AppData\Local\Programs\Python\Python39'
# mkdir testPY

就可以建立虛擬環境:

# 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 執行檔的路徑:

# 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 套件:

# pipenv install cowsay
Installing cowsay...
Resolving cowsay...
...
pipenv run.

專案資料夾的異動

建立好專案的虛擬環境後, 如果專案資料夾要異動, 都有需要注意的地方。

複製專案資料夾

如果你想要將已經建立的專案資料夾複製到其他地方使用, 只要在複製後重新執行 pipenv install 指令即可, 例如:

# 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

這樣就可以複製出一個相同版本的虛擬環境, 而且也會自動安裝原來虛擬環境中的套件:

# 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 指令刪除虛擬環境之後再搬移, 重新建立虛擬環境:

# 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 檔:

# 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 指令:

# 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 移除:

# cd ..
# rm -r -Force test5
# pyenv uninstall 3.10.8
pyenv: Successfully uninstalled 3.10.8

由於我們沒有移除虛擬環境, 所以如果在同樣位置再次建立 test5 資料夾:

# mkdir test5
# cd test5

再重新進入資料夾建立虛擬環境:

# 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 版。

即使你指定安裝版本也沒用:

# 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'

也正因為如此, 才會不斷強調要搬移或是移除專案前, 最好先移除虛擬環境, 這樣既不會佔用空間, 也不會造成意外的結果。