virtualenv 運作原理以及Python 載入 sys.path 的過程

今天試了 virtualenv 覺得滿有趣的, 就研究了一下它怎麼換掉 site-packages, 搞出獨立的 site-packages。關鍵在於 python 載入 sys.path 的過程 ( python 會依 sys.path 內的路徑找 package / module )。

site 所言, python 預設會載入 site.py 來載入 sys.path 的主要內容 (但可用 python -S 取消這點)。這就是 virtualenv 切入的點, 它利用 python 找到 site.py 的規則, 讓 python 載入 virtualenv 修改過的 site.py, 於是就能掌控之後的載入內容 (如不要載入 global site-packages)。

詳細的的規則參照 site, 這裡以 Ubuntu + python2.5 為例。執行 /X/bin/python 後, 若存在目錄 /X/lib/python2.5/ 的話, sys.prefix 會存成 /X (我試的結果是, 若找不到 /X/lib/python2.5/, 會存成 /usr), sys.path 的內容依序如下:
  1. 被執行的 python script 的位置。比方執行 python /home/fcamel/main.py, 就是 /home/fcamel
  2. sys.prefix + "/lib/python2.5/site.py"
  3. site.py 載入的東東, 懶得看到底做了那些事
  4. ...
  5. shell 內設的環境變數 PYTHONPATH
  6. ...
剩下一些細節之後有機會再來弄清楚。從 site.py 裡沒看到 PYTHONPATH, 而 python 原始碼裡有類似的東西 ( Modules/getpath.c )。

回歸正題, 建立 virtualenv 時, virtualenv 會產生一個目錄, 其中包含一個 shell script 。執行 script 後會換掉 PATH, 讓使用者執行 python 時會先執行到 virtualenv 放的 python。這個 python 和系統裝的 python 一模一樣, 目的只是要換掉 sys.prefix, 藉此控制 site.py 載入的路徑。比方說執行到 /home/fcamel/my_env/bin/python, 若它發現能找到 /home/fcamel/my_env/lib/python2.5/, 就會把 sys.prefix 設成 /home/fcamel/my_env, 於是就能載入自己放的 site.py 了 (即 /home/fcamel/my_env/lib/python2.5/site.py )。

留言

這個網誌中的熱門文章

(C/C++ ) 如何在 Linux 上使用自行編譯的第三方函式庫

熟悉系統工具好處多多

virtualbox 使用 USB 裝置