[Python] 解決 import 相對路徑執行問題
絕對 vs 相對 兜幾!
應該很多人都知道 python 在 import 套件的時候可以用絕對或相對路徑,兩者各有好壞,最近剛好有個專案兩種都有用到,剛好可以整理一下,使用時機和今天遇到的問題.
狀況是我和同事共同開發一個專案,我開發 REST API部分,同事負責寫 Module ,剛開始腦袋沒想清楚檔案結構,所以分在不同目錄開發,後來偷懶懶得寫 install file 想說直接 copy 過來就發生了一些問題,靠著改成 import 相對路徑解決.
BUT! 凡事就是這個 BUT,有些程式 run 不起來
··· 崩╰(〒皿〒)╯潰····
來個簡化版的結構
src/
app.py
errors.py
app.py
from .errors import HaErrordef main():
print('hi')
raise HaError()if __name__ == '__main__':
main()
errors.py
class HaError(Exception):
pass
但是
··· 崩╰(〒皿〒)╯潰····
雖然想說應該是路徑的問題但是就算回到上一層也還是崩潰
後來終於想到還有一招沒用 python -m
python -m 可以把 python module 當成 script 來執行(https://www.python.org/dev/peps/pep-0338/)重點是看一下用 python 和用 python -m 差在哪裡,為什麼直接用 python 找不到相對應的 module.
修改一下程式內容:
app.py
from .errors import HaErrordef main():
print(type(__name__), __name__)
print(type(__package__), __package__)print('hi')
raise HaError()if __name__ == '__main__':
main()
errors.py
print(type(__name__), __name__)
print(type(__package__), __package__)class HaError(Exception):
pass
加入兩行:
print(type(__name__), __name__) # 執行程式的名字
print(type(__package__), __package__) # 屬於哪個 package
再執行一次
前面兩個是 從 errors.py 出來的結果,透過 python -m,import 其他 package 時,其他 package 的名字會呈現 package+module name , package 的名稱自然是 src.
下面兩個是 app.py ,直接執行的程式(app.py), __name___ 就會等於 __main__,package 名稱也會是 src.
值得注意的是 python -m 如果要帶 package name 進去,一定要在最外面那層(跟 package 同一層)執行才有用,進到 src 後執行也會找不到路徑(嚴格來說是找不到 package name).
回到原本的問題,要解決 python 路徑大致有四種解法:
- 全部都寫絕對路徑,但是如果目錄很深,又有可能移動會很難寫
- 像本篇解法一樣,寫相對路徑
- 把 package 的路徑加入 PYTHONPATH
- 用 setuptools 另外寫一個 setup.py ,使用 python setup.py install 安裝套件
至於什麼時候用哪個就看情境了.