撥開 Python, pip, site-packages 的藍色蜘蛛網 💢
處理過 Python 環境問題的人看到上圖大概會有一些感覺... 😝
Python 環境問題可能是:
- 電腦有超多 Python 版本,有
python
,python2.7
,python3
,python3.4
,python3.6
,python9527
… 每個版本是從哪裡來的最後也搞不清楚,brew
,apt-get
,yum
,anaconda
,pip
,easy_install
,pyenv
, OS 自己帶的,自己抓的執行檔,自己抓 tarball 來 build 的。慘的話,可能同樣版本還有不同份在不同 path 上 - 電腦有好幾個
pip
版本,有pip
,pip3
, 可能還有pip3.4
,pip3.6
, 然後這些 pip 版本自己又有分版本,像是pip 10.0.1
或pip 9.0.1
這種。 - 不知道 pip 跟 python 的關係是什麼
- 不知道 python 在 import 時,dir 尋找順序是什麼
pip install
有時因為權限問題而提示我可以加個--user
,但不懂加了是裝在哪,不加又是裝在哪- 大概知道 python 的 package 好像是裝在
site-packages
這個資料夾,結果後來發現電腦裡有幾百萬個site-packages
- Python 升級之後,裝過的 package 又不知道跑到哪裡去了,一直
ImportError: No module named ‘xxx’
(或ModuleNotFoundError: No module named ‘xxx’
)
這些問題我常常看到在身邊還有網路上有人問,也都是我以前真實碰過的問題。自己本來是可以用就好,Python 書也不太會把這些解釋得很清楚(書通常是在講 import 邏輯或是 setuptools
, distutils
等等)。而最近不想含混過去,就稍微釐清了一下以上問題,然後筆記一下重點,希望讓也想了解的人節省一點時間。
先不討論衍生的東西
然後,光是以上這些問題就算是一個主題了,所以這裡先不試著去討論後來衍生出的 virtualenv
, venv
, pyenv
, pyvenv
, virtualenvwrapper
, pipenv
, pyenv-virtualenvwrapper
…,這些東西都是為了解決一些既有問題而生的 tool,其中有幾個可以說是必備。如果有興趣我覺得這篇 Stack Overflow 的整理不錯。
關於 import 邏輯,還有 $PYTHONPATH
這個環境變數,這裡也不贅述了;簡單的話可以直接咕狗,我是建議看書比較系統化跟完整,推薦 精通 Python 3 程式設計
跟 Python 參考手冊(Python Essential Reference, 4/e)
。
幾個簡單的大觀念:
建議用這樣的順序理解下去 ↓
到處都有 site-packages 資料夾 🌏
site-packages
是一個資料夾,放我們安裝的 python package,可能到處都有- 每安裝一個 python 版本,對於版本
X.Y
都有各自的site-packages
。
比方說 python 3.4 跟 python 3.6 都各自有分開的site-packages
在不同的路徑,而 python 3.6.1 跟 python 3.6.2 的是同一個 - 每個 user 可以有自己的
site-packages
,在 home 目錄下的某個地方(如果有興趣可以 googlesite
這個 package 的site.USER_SITE
,或看這個官方文件(for python 3.7)) ipython
跟一些 tool 裝了之後也有自己的site-packages
pip / pip3 指令在結構上是什麼? 👭
pip 是個 python script,也是個 python package
- python script: 我們執行的
pip
,只是一個開頭的 python script,裡面會再去 import 電腦裡「某一個」site-packages
資料夾裡「真正的」pip
package 來跑。(推薦用which pip
去看一下 script 內容) - python package: 承上,至於會 import 到哪一個
site-packages
下的pip
package,是看我們怎麼執行pip
(稍後細說)
pip 版本有兩個層次:
- 分
pip
或pip3
:
pip 用來管理 python 2.x 用的 package,而 pip3 用來管理 python 3.x 用的 package。他們各自獨立,pip 升級不會變成 pip3,要裝 pip3 也不需要先有 pip。 pip
(或pip3
) 有自己本身(pip package)的版本:
執行pip --version
可以看到…
pip 10.0.1 from /usr/local/lib/python2.7/site-packages/pip (python 2.7)
這裡的 10.0.1
就是 pip package 的版本 (也可以看到實際上跑到的 pip package 在哪個資料夾)
以上 pip3
跟 pip
都是一樣道理,有興趣可以從 which pip3
當作源頭開始追看看 😃
那 python import 時會去看哪些 dir? 📂
想知道是從哪些路徑,用什麼順序去找 package,這裡有兩個方法:
- 第一個:在 python 裡先
import sys
再看sys.path
的值
- 第二個:在 shell 執行
python -m site
(或python3 -m site
)
可以觀察一下這兩個方法的輸出,有一些差別。
用不同方式執行 pip ,會 import 到不同資料夾的 pip package 😕
幾種方式的差別:
1. pip
2. python /usr/local/bin/pip
3. python -m pip
- 直接執行
pip
:
shell 會找到$PATH
裡第一個pip
script,依照這 script 裡的shebang
(就是#!/usr/bin/python
這種東西)來決定用哪個版本的 python 跑,所以會用那個版本 python 的sys.path
去找pip
package 來用。有興趣的人可以試試去改 shebang 的版本,看會發生什麼事。 - 用
python
跑指定路徑的pip
script:
這樣shell 執行的python
版本會壓過 shebang 指定的 python 版本。比方說,這裡執行的python
如果是 2.7,就算 shebang 雖然指定要用 python3 跑,最後還是會用 2.7 去跑;所以,這樣就會從 python2.7 的sys.path
裡去找pip
package。 - 用
python
的 -m 參數跑pip
:
這樣會去用 shell 執行的python
版本的sys.path
裡的pip
package(好繞…)。如果 python 指令的版本是 2.6,那就是跑 2.6 裡的pip
package。
man page 說明:
-m module-name: Searches sys.path for the named module and runs the corresponding .py file as a script.
以上不管是哪一種,如果沒有任何一個 site-packages
裡有 pip,就 import error 跑不起來。
跑了 pip install,那東西到底被裝到哪裡去了? 😕
pip install
會有預設安裝的 dir,也會因為各種參數去改變,像是:--target
, --user
, --prefix
, --root
等等。
有兩個方法可以看被裝在哪:
- 最簡單的方法是剛才講到的,
pip --version
(或是pip -V
)會顯示目前這個 pip 是跑哪一個site-packages
下的pip
package ,這個路徑就是 install 時會放的 dir - 或,比較間接的方法,先用
pip list
列出所有已經安裝的 pkg,然後用pip show [某pkg]
就會寫 Location 在哪
如果是用 pip3,方法也是一模一樣。
↑ 以上這些,我覺得是最重要的 😃
其他你可能想知道的:
如何安裝 pip 本身(不是用 pip install 去裝東西)
如果電腦裡沒有 pip
或是需要重新安裝,有好幾種安裝 pip
的方法:
- 可以透過 OS 裡
apt
/yum
這種 package manager - 也可以下載一個 get-pip.py 檔案然後用
python
去執行這個 script。這種就會跟文章前面所敘述的一樣,用不同版本python
去跑會有差。
升級 pip 本身
pip
可以用自己來升級自己,像是從9.0.1
升級到10.0.1
。
這裡有個很有意思的問題…現在如果要升級 pip3,command 要怎麼下?可能是:
pip3 install --upgrade pip
pip install --upgrade pip3
pip3 instal --upgrade pip3
pip install --upgrade pip
猜猜哪個是對的做法?ㄎㄎ
dist-packages 跟 site-packages 的差別
有時候會看到這兩個詞似乎是可以交換用的,差別在哪?可以看 [這篇],簡略的說是Debain/Ubuntu 為了降低 conflict 的慣例。
Python 環境的問題錯綜複雜,如果有寫錯或是需要更新的,歡迎在留言更正我一下噢! 😃 🙇
有幾位朋友幫忙 review 了這篇文章,感謝!
Reviewer
(A-Z): Askeing Yen / Kilik Kuo / Paul Yang / samuelololol / Vincent Liu / Walter Chen
一些關於我的資訊: