Python 模組找不到?帶你探索 Python 搜索模組的秘密!

我們常常都在 Python 中 import 套件
但明明裝了套件,卻出現找不到套件時該怎麼辦呢?
Python 中要引入 module 的時候,我們都知道要用 import,像是下面這樣:
import os
或是想要動態引入的話,可以透過 module 名稱用 importlib
引入:
import importlib
os = importlib.import_module("os")
但到底 Python 是怎麼找到我們要引入的 module?
sys.path
當 Python 開始執行時,Python 的 module 搜尋清單會被建立,這個清單會被存放在 sys.path
因此我們可以透過印出 sys.path
來得知目前 Python 會從哪些路徑尋找 module
而第一個搜尋路徑代表著 Python Script 所存在的目錄
import sys
print(sys.path)
[
'/home/ubuntu',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/.local/lib/python3.10/site-packages',
'/usr/local/lib/python3.10/dist-packages',
'/usr/lib/python3/dist-packages'
]
而這個 sys.path 是可以自己做修改的,這樣就可以讓 Python 到這裡去找 module
import sys
sys.path.append("/path/to/module")
-m
和 -c
與使用 python3 test.py
不同,如果我們使用 -m
或是 -c
的話,第一個搜尋路徑代表著都是執行指令的路徑,而非 script 所在的目錄。
使用 -c
,第一個路徑會是空字串,這是相對路徑,代表著執行 python3 -c
這個指令時所在的路徑
例如你在 /home/ubuntu/test
的路徑下執行 python3 -c "import sys; print(sys.path)"
,則第一個搜尋路徑代表著就是 /home/ubuntu/test
而因為有 zip import 的功能,也就是把 lib 壓縮成 zip file,所以路徑上也會有 .zip
[
'',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/.local/lib/python3.10/site-packages',
'/usr/local/lib/python3.10/dist-packages',
'/usr/lib/python3/dist-packages'
]
換作使用 -m
的話,如果我在 /home
目錄下,執行 python3 -m ubuntu.test
的指令,則第一個搜尋路徑就會是 /home
雖然與 -c
不同,不是空字串,但所代表的含意是相同的,都是指向執行指令時的路徑
[
'/home',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/.local/lib/python3.10/site-packages',
'/usr/local/lib/python3.10/dist-packages',
'/usr/lib/python3/dist-packages'
]
總結以上,如果我們在 /a/b/c
的目錄下執行下列兩種指令,兩者差別在於是搜尋路徑是包含 /a/b/c
還是 /a/b/c/d
。
python3 d/xxx.py
: 包含/a/b/c/d
。python3 -m d.xxx
: 包含/a/b/c
。
PYTHONPATH
有時候我們只是要測試某些正在開發的檔案,但這些檔案又沒有放在預設的搜尋清單中
這時候就可以透過 PYTHONPATH
這個環境變數來快速加入到 sys.path 中
export PYTHONPATH="test"
python3 -c "import sys; print(sys.path)"
[
'',
'/home/ubuntu/blog/yyblog/test',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/.local/lib/python3.10/site-packages',
'/usr/local/lib/python3.10/dist-packages',
'/usr/lib/python3/dist-packages'
]
不過,PYTHONPATH
也會影響到 shell 中其他的 Python 程式,因此要謹慎使用。
Virtual Environment
一般來說,如果我們在虛擬環境裡面,我們只能使用虛擬環境中有安裝的 package,系統上安裝的是不能 import 的
但我們可以透過修改虛擬環境資料夾內的 pyvenv.cfg
,例如虛擬環境在 /home/ubuntu/env
,檔案就會是 /home/ubuntu/env/pyvenv.cfg
home = /usr/bin
include-system-site-packages = false
version = 3.10.12
我們將其中的 include-system-site-packages
改成 true
,就可以使用系統的 package 了
這點也可以從 sys.path 上看到,在修改前,include-system-site-packages
是 false
[
'',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/env/lib/python3.10/site-packages'
]
修改成 true
之後就多了系統的 package 安裝路徑了
[
'',
'/usr/lib/python310.zip',
'/usr/lib/python3.10',
'/usr/lib/python3.10/lib-dynload',
'/home/ubuntu/env/lib/python3.10/site-packages',
'/home/ubuntu/.local/lib/python3.10/site-packages',
'/usr/local/lib/python3.10/dist-packages',
'/usr/lib/python3/dist-packages'
]
另外,如果在使用 venv 建立虛擬環境的時候,可以加上 --system-site-packages
,這樣預設就可以使用系統的 package 了,例如:
python3 -m venv env --system-site-packages
dist-packages / site-packages
Debian 系統中,為了防止衝突,有做了一些調整:
- site-packages: 使用者安裝的套件都會被放在
site-packages
中。 - dist-packages: Debian 系統中,系統會自帶或是可以透過
apt
安裝 Python 套件,為了和使用者安裝的作區別,因此會被放置在dist-packages
中,而 pip 安裝的也算是此類。
例如:
- 系統自帶 or
apt
安裝:/usr/lib/python3/dist-packages
pip
安裝在 system:/usr/local/lib/python3.10/dist-packages
,多了個 local,進一步作區隔pip
安裝在 user:/home/<user>/.local/lib/python3.10/site-packages
- 虛擬環境
pip
安裝:path/to/env/lib/python3.10/site-packages
Reference
- https://stackoverflow.com/questions/301134/how-can-i-import-a-module-dynamically-given-its-name-as-string
- https://docs.python.org/3/library/importlib.html#importlib.import_module
- https://docs.python.org/3/library/sys_path_init.html
- https://stackoverflow.com/questions/3371136/revert-the-no-site-packages-option-with-virtualenv
- https://stackoverflow.com/questions/34822593/why-does-sys-path-have-c-windows-system-python34-zip
- https://docs.python.org/zh-tw/3.13/library/venv.html
- https://stackoverflow.com/questions/9387928/whats-the-difference-between-dist-packages-and-site-packages
- https://blog.csdn.net/qq_41897154/article/details/109586312
如果你覺得這篇文章有用 可以考慮贊助飲料給大貓咪