TL;DR
開發稍有規模的Python專案時,常會在 import 自定義的模組時遇到狀況,本篇筆記整理使用 absolute import 及 relative import的時機。
Module VS Package
首先我們先定義這兩個名詞 :
Module
Module 指的是任何定義在 *.py 中的 Function
:::python
# module_a.py
def function_a():
    print("This is a example function!")
寫在 .py 檔中的 Function 可以被其他Python呼叫:
:::python
# main.py
from module_a import function_a
if __name__ == "__main__":
    function_a()
Package
Package 則是將一群 Module 的集合,使用特別的方法將數個 Module 封裝起來:
- 將一至多個 Module放入相同的資料夾.
- 在資料夾中加入一個空白的 __init__.py
假設我們想將三個 Module 封裝成一個 Package:
- module_a.py
- module_b.py
- module_c.py
根據上面兩個原則,我們需要調整為以下結構:

當上述條件皆滿足,這個資料夾就會被視為一個 Package,可以被執行檔載入 :
# main.py
from my_package.module_a import xxx
    ```
---
# Absolute Import VS Relative Import
Python在 Import 檔案時有兩種不同的方式:
## Absolute Import
上述的兩個例子
```python
# main.py
from module_a import function_a # 例子(1)
from my_package.module_a import function_a  # 例子(2)
其實都是屬於 Absolute Import,所謂的 Absolute Import 指的是
從
系統路徑中嘗試讀取Package或Module
系統路徑是一連串的路徑,在Python執行下列指令,會得到一包含許多路徑的 List.
import sys
print(sys.path) # 印出系統路徑
其中值得注意的是: 在執行時,當下的路徑會被自動加入sys.path中
在下列情境中:

如果執行 main.py 是可以運行的:
from module_a import function_a
if __name__ == "__main__":
    function_a()
當 main.py 被執行時,會自動將 main.py 當前的資料夾路徑插入 sys.path(系統路徑)中的第一個位置。
Import Module 或 Package 時會依序檢查 sys.path 的路徑,此時排在 sys.path首位的路徑就是 main.py 當前的位置(也正是 module_a.py 所在的位置),所以可以正確 import.
然而 Absolute Import 有一個限制 : 名稱必須要是Unique
來個極端的例子,假設現在的 sys.path 長這樣:
["/home/minglun/", “/home/minglun/project”]
如果我們執行下列程式碼:
from module_a import function_a
結果在 /home/minglun 及 /home/minglun/project 兩個位置中都有一個 module_a.py,那Python怎麼知道要使用哪一個檔案呢?
它無從得知,此時就會發生錯誤!
此時我們就需要 Relative Import
Relative Import
從檔案當前位置為基準,尋找對應的檔案

相同 Package 中的 module 如果需要互相引用,例如 module_a.py 要引用 module_b.py
# module_a.py
from .module_b import function_b # 使用相對路徑指定當前的module_b.py
同一個 Package 中的 Module 如果需要互相引用,使用 Relative Import 可以避免路徑混淆。
幾個重要原則
- 避免在Module中放置定義以外的東西:Module是用來被Import後執行的,執行的程式碼最好放在外部(上述案例中的main.py),否則容易發生執行上的混亂。
- 同一個 Package中的Module互相引用 : 使用Relative Import
- 不同 Package中的Module互相引用 : 使用Absolute Import
- 執行檔(main.py)引用模組: 使用Absolute Import
只有同一個
Package中的Module要互相引用,才用Relative Import,否則都用Absolute Import