如何在macOS上預設 Python 3

Hsin-Cheng Chao
Apr 26, 2020

--

我必須很羞恥的承認,好幾次我開始了一個 Side Project 但是都在不久之後就放棄了,常常原因都是因為要搞定環境本身就消磨去了我大部分的熱情。所以我這次決定徹底把這一些東西搞懂然後寫下來,之後自己就比較沒有放棄的藉口了。

遇到的問題

我在要開始一個專案的時候通常遇到的第一個問題就是Python的版本,一般來說都是希望用最新最潮的 Python 3,但我的Mac電腦上面內建的Python版本是 2.7.16 。然後之前不知道在做哪一個專案的時候我也安裝過了Python 3 可是這個版本的問題是我每一次要執行 Python指令的時候都必須輸入 python3 或是 pip3 (多打一個3) 不然他就會使用預設的版本 (python 2.7.16) 一不小心忘了就會用執行錯誤的Python。

➜  ~ python --version
Python 2.7.16
~ which python
➜ ~ which python
/usr/bin/python
➜ ~ python3 --version
Python 3.7.3
➜ ~ which python3
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

本來想說就直接把系統預設的版本改掉就好了,但參考過了一些網路上的資源之後 [1] 發現最好還是不要更動也不要依賴系統的預設版本,而網路上大部分資源推薦的方法是使用 pyenv 這個工具,基於好奇我就對這個套件做了一些研究。

套件評估

優點

第一是他是一個開源的專案,在Github上面可以直接看到原始碼,比較不擔心他對內藏什麼可疑的邏輯。第二是他是透過Bash script實作,本身幾乎沒有其他程式語言貨的套件相依性,因此設定時較不容易落入安裝套件的地獄輪迴。第三是他的文件非常詳細,很仔細的解釋了這個套件本身是如何運作,搭配第二點和一些指令就可以很容易地了解它運作的方法,之後也比較容易除錯。第四點是安裝容易,簡單的 brew install 就可以搞定了。

運作原理

想要了解pyenv如何運作前必須先瞭解 Linux作業系統上是如何去執行 python 或是 pip 這類的指令。當我們在終端機輸入指令實,作業系統會通過 PATH這個環境變數由左至右一個一個資料夾去尋找有沒有名字一樣的執行檔,舉例來說,如果你透過 echo指令看見 PATH這個環境變數如下:

➜  ~ echo $PATH
/usr/local/bin:/usr/bin:/bin

當你想要執行`python`指令的時候,作業系統會先去 /usr/local/bin 底下尋找有沒有名叫做 python 的檔案可以執行,如果沒有的話就再去 /usr/bin 尋找,再沒有的話就去找 /bin 。這也代表了如果好幾的資料夾裡面都有名字一樣的執行檔的話,作業系統會使用第一個找到的。pyenv 就是透過修改環境變數來動態切換python執行的版本。

理解 Shims

Shims (這裡姑且把它翻譯成墊片好了) 就是透過動態改變環境變數來讓多個版本的 Python 同時相容在電腦上然後可以輕易地切換。pyenv 在 PATH環境變數的前面加上的一個 shims,然後去改變執行的 pythonpip 指令的版本。因此可以做到在不同的資料夾底下(例如 ~/project1/ 和 ~/project2/)執行 python 時系統會自動切換不同的版本 (python 2.7 vs python 3.7)。

$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

pyevn 在 PATH環境變數最前面加上一個他自己的資料夾,來”欺騙”作業系統去執行pyenv版本的python,因此當你執行 python 時,作業系統會根據上述的規則去 shims資料夾底下找名叫 python 的執行檔,而這個 pyenv版本的執行檔則會做下面幾件事情:

  1. 檢查是否有 PYENV_VERSION 這個環境變數,如果有的話就執行這個版本的 python
  2. 如果沒有 PYENV_VERSION 的話檢查目前執行的資料夾裡面有沒有 .pyenv-version 這個隱藏檔案(這個檔案可以透過執行 pyenv local 來產生),如果有的話就用它上面指定的版本。
  3. 如果還是沒有的話就順著資料夾一層一層的往上找,如果找到 .pyenv-version 的話就用那個版本
  4. 如果一直到根目錄都沒有找到 .pyenv-version 的話就去檢查 $($pyenv root)/version 這個檔案(這個檔案可以透過執行 pyenv global來產生),再沒有的話就讓作業系統繼續去找下一個資料夾。

執行

在上述 pyenv 的簡單設計底下,用戶只要輸入 pyenv install a.b.c pyenv 便會將相對應版本的執行檔下載至相對應的資料夾 $(pyenv root)/version/a.b.c 以供執行,因此只要在每次開始 side project時設定一次,之後就不用再擔心 Python 執行版本的問題啦!

缺點

Python常見套件管理工具 virtualenv 也是透過類似的方法去修改 PATH環境變數來切換套件版本,因此同時使用pyenv跟virtualenv的話會有衝突。官方是建議使用 pyenv-virtualenv 這個擴充套件來解決不相容的問題(要多下載一個套件很不方便)。

結論

Pyenv 對於做Side Project的人來說,解決了Python版本的問題,但是 Python套件的管理還是需要仰賴virtualenv等工具,雖說Python 3.3之後,Virtualenv已經有一部分進入Python的標準函式庫,因此可能未來版本管理會變得更簡單。但是單就在自己電腦上跑的Side Project這樣已經算是很不錯的工具了。等我使用過一陣子之後再看看有沒有其他心得,就這樣啦!

參考資料

[1]: https://opensource.com/article/19/5/python-3-default-mac

--

--

Hsin-Cheng Chao
Hsin-Cheng Chao

Written by Hsin-Cheng Chao

Full-stack python engineer by day, Self-Driving Car student by night!