# 12. 虛擬環境與套件

## 12.1. 簡介

Python 應用程式通常會用到不在標準函式庫的套件和模組。應用程式有時候會需要某個特定版本的函式庫，因為這個應用程式可能需要某個特殊的臭蟲修正，或是這個應用程式是根據該函式庫特定版本的介面所撰寫。

這意味著不太可能安裝一套 Python 就可以滿足所有應用程式的要求。如果應用程式 A 需要一個特定的模組的 1.0 版，但另外一個應用程式 B 需要 2.0 版，那麼這整個需求不管安裝 1.0 或是 2.0 都會衝突，以致於應用程式無法使用。

解決方案是建立一個虛擬環境 (virtual environment)，這是一個獨立的資料夾，並且裡面裝好了特定版本的 Python，以及一系列相關的套件。

不同的應用程式可以使用不同的虛擬環境。以前述中需要被解決的例子中，應用程式 A 能夠擁有它自己的虛擬環境，並且是裝好 1.0 版，然而應用程式 B 則可以是用另外一個有 2.0 版的虛擬環境。要是應用程式 B 需要某個函式庫被升級到 3.0 版，這並不會影響到應用程式 A 的環境。

## 12.2. 建立虛擬環境

用來建立與管理虛擬環境的模組叫做 `venv`。`venv` 將安裝執行命令的 Python 版本（如 `--version` 選項所報告的）。例如使用 `python3.12` 執行命令將安裝 3.12 版本。

在建立虛擬環境的時候，在你決定要放該虛擬環境的資料夾之後，以腳本 (script) 執行 `venv` 模組並且給定資料夾路徑：

    python -m venv tutorial-env

如果 `tutorial-env` 不存在的話，這會建立 `tutorial-env` 資料夾，並且也會在裡面建立一個有 Python 直譯器的複本以及不同的支援檔案的資料夾。

虛擬環境的常用資料夾位置是 `.venv`。這個名稱通常會使該資料夾在你的 shell 中保持隱藏，因此這樣命名既可以解釋資料夾存在的原因，也不會造成任何困擾。它還能防止與某些工具所支援的 `.env` 環境變數定義檔案發生衝突。

一旦你建立了一個虛擬環境，你可以啟動它。

在 Windows 系統中，使用：

    tutorial-env\Scripts\activate

在 Unix 或 MacOS 系統，使用：

    source tutorial-env/bin/activate

（這段程式碼適用於 bash shell。如果你是用 csh 或者 fish shell，應當使用替代的 `activate.csh` 與 `activate.fish` 腳本。）

啟動虛擬環境會改變你的 shell 提示字元來顯示你正在使用的虛擬環境，並且修改環境以讓你在執行 `python` 的時候可以得到特定的 Python 版本，例如：

    $ source ~/envs/tutorial-env/bin/activate
    (tutorial-env) $ python
    Python 3.5.1 (default, May  6 2016, 10:59:36)
      ...
    >>> import sys
    >>> sys.path
    ['', '/usr/local/lib/python35.zip', ...,
    '~/envs/tutorial-env/lib/python3.5/site-packages']
    >>>

要停用虛擬環境，輸入：

    deactivate

於終端機中。

## 12.3. 用 pip 管理套件

你可以使用一個叫做 pip 的程式來安裝、升級和移除套件。`pip` 預設會從 Python Package Index 安裝套件。你可以透過你的網頁瀏覽器瀏覽 Python Package Index。

`pip` 有好幾個子命令："install"、"uninstall"、"freeze" 等等。（可以參考安裝 Python 模組指南，來取得 `pip` 的完整說明文件。）

你可以透過指定套件名字來安裝最新版本的套件：

    (tutorial-env) $ python -m pip install novas
    Collecting novas
      Downloading novas-3.1.1.3.tar.gz (136kB)
    Installing collected packages: novas
      Running setup.py install for novas
    Successfully installed novas-3.1.1.3

你也可以透過在套件名稱之後接上 `==` 和版號來指定特定版本：

    (tutorial-env) $ python -m pip install requests==2.6.0
    Collecting requests==2.6.0
      Using cached requests-2.6.0-py2.py3-none-any.whl
    Installing collected packages: requests
    Successfully installed requests-2.6.0

要是你重新執行此命令，`pip` 會知道該版本已經安裝過，然後什麼也不做。你可以提供不同的版本號碼來取得該版本，或是可以執行 `python -m pip install --upgrade` 來把套件升級到最新的版本：

    (tutorial-env) $ python -m pip install --upgrade requests
    Collecting requests
    Installing collected packages: requests
      Found existing installation: requests 2.6.0
        Uninstalling requests-2.6.0:
          Successfully uninstalled requests-2.6.0
    Successfully installed requests-2.7.0

`python -m pip uninstall` 後面接一個或是多個套件名稱可以從虛擬環境中移除套件。

`python -m pip show` 可以顯示一個特定套件的資訊：

    (tutorial-env) $ python -m pip show requests
    ---
    Metadata-Version: 2.0
    Name: requests
    Version: 2.7.0
    Summary: Python HTTP for Humans.
    Home-page: http://python-requests.org
    Author: Kenneth Reitz
    Author-email: me@kennethreitz.com
    License: Apache 2.0
    Location: /Users/akuchling/envs/tutorial-env/lib/python3.4/site-packages
    Requires:

`python -m pip list` 會顯示虛擬環境中所有已經安裝的套件：

    (tutorial-env) $ python -m pip list
    novas (3.1.1.3)
    numpy (1.9.2)
    pip (7.0.3)
    requests (2.7.0)
    setuptools (16.0)

`python -m pip freeze` 可以複製一整個已經安裝的套件清單，但是輸出使用 `python -m pip install` 可以讀懂的格式。一個常見的慣例是放這整個清單到一個叫做 `requirements.txt` 的檔案：

    (tutorial-env) $ python -m pip freeze > requirements.txt
    (tutorial-env) $ cat requirements.txt
    novas==3.1.1.3
    numpy==1.9.2
    requests==2.7.0

`requirements.txt` 可以提交到版本控制，並且作為釋出應用程式的一部分。使用者可以透過 `install -r` 安裝對應的的套件：

    (tutorial-env) $ python -m pip install -r requirements.txt
    Collecting novas==3.1.1.3 (from -r requirements.txt (line 1))
      ...
    Collecting numpy==1.9.2 (from -r requirements.txt (line 2))
      ...
    Collecting requests==2.7.0 (from -r requirements.txt (line 3))
      ...
    Installing collected packages: novas, numpy, requests
      Running setup.py install for novas
    Successfully installed novas-3.1.1.3 numpy-1.9.2 requests-2.7.0

`pip` 還有更多功能。可以參考安裝 Python 模組指南，來取得完整的 `pip` 說明文件。當你撰寫了一個套件並且想要讓它在 Python Package Index 上可以取得的話，可以參考 Python packaging user guide。