[Python] 解決 import 相對路徑執行問題

Bryan Yang
A multi hyphen life
5 min readJan 23, 2018

絕對 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 路徑大致有四種解法:

  1. 全部都寫絕對路徑,但是如果目錄很深,又有可能移動會很難寫
  2. 像本篇解法一樣,寫相對路徑
  3. 把 package 的路徑加入 PYTHONPATH
  4. 用 setuptools 另外寫一個 setup.py ,使用 python setup.py install 安裝套件

至於什麼時候用哪個就看情境了.

References:

--

--

Bryan Yang
A multi hyphen life

Data Engineer, Data Producer Manager, Data Solution Architect