Learning Objectives
- 定義模組(module):一個 .py 檔就是一個模組
- 使用模組:import、import ... as、from ... import
- 用 dir() 查看模組裡定義了哪些名稱
- __name__ 內建變數的用法:分辨「直接執行」與「被匯入」
為什麼需要模組
程式越寫越長,全部塞在同一個檔案裡會很難找、也很難重複使用。模組(module)
就是把相關的函數、類別與變數放在同一個 .py 檔,其他程式要用時再匯入。
- 模組名稱=檔名去掉
.py:support.py就是support模組 - 模組可以定義函數、類別、變數,也可以有直接執行的程式碼
- 你已經用過不少模組:
math、random都是 Python 標準函式庫的模組
本課的範例會在工作目錄先放好 support.py、bmi.py 這些模組檔,你可以在「檔案」分頁看到它們的內容。
動畫播放時,記憶體區的框架標題如果標示 support.py,代表那一步正在執行模組裡的程式。
import:匯入整個模組
import support 會在模組搜尋路徑找到 support.py,從頭執行一次,然後在主程式建立一個名稱 support 指向這個模組。注意:第二次 import support 時,執行箭頭有沒有再跑進 support.py?
import ... as 與 from ... import
import support as sp 幫模組取別名;from support import show_name 則把 show_name 這個名稱直接放進主程式,呼叫時不必加前綴。看右邊主程式的變數:sp 指向模組,show_name 指向函數。最後自己定義同名函數時,show_name 指向的東西換掉了。
三種匯入寫法比較
| 寫法 | 之後怎麼用 | 適合的情況 |
|---|---|---|
import support |
support.show_name('Rose') |
一般情況;看得出名稱來自哪個模組 |
import support as sp |
sp.show_name('Rose') |
模組名稱很長,例如 import numpy as np |
from support import show_name |
show_name('Rose') |
只需要模組裡的少數幾個名稱 |
from support import * |
show_name('Rose') |
方便但要小心:所有名稱都倒進來,容易蓋掉同名的變數 |
不論
import幾次、用哪一種寫法,同一個模組只會載入一次;之後的 import 只是取用已經載入的模組。
dir():模組裡有哪些名稱
dir(模組) 傳回模組內定義的所有名稱,是排序過的串列(list)。__ 開頭結尾的是 Python 自動加的系統名稱,例如 __name__、__doc__。
想一想:匯入
下面的程式會印出什麼?
from math import sqrt
print(sqrt(16))
下面的程式會印出什麼?
from math import pi
pi = 3
import math
print(pi, math.pi)
import numpy as np 之後,下面哪一種寫法是正確的?
__name__:我是被直接執行,還是被匯入?
每個模組都有一個內建變數 __name__,它的值有兩種可能:
| 情況 | __name__ 的值 |
|---|---|
直接執行這個檔案(python bmi.py) |
'__main__' |
被其他程式 import |
模組名稱,例如 'bmi' |
所以模組常在最後寫:
if __name__ == '__main__':
# 只有直接執行這個檔案時才會跑(例如測試、示範)
main()
這樣同一個檔案「自己執行時」可以當成小程式,「被匯入時」只提供函數,不會突然跳出 input() 問身高體重。
另外,__file__ 代表模組的檔名。下面兩個動畫用同一份 bmi.py,一次被匯入、一次直接執行。
被匯入時:if 區塊不會執行
主程式 from bmi import BMI。注意 bmi.py 印出的 __name__ 是什麼,以及執行箭頭在 if __name__ == '__main__': 之後跳到哪裡。
直接執行時:if 區塊會執行
同樣的程式,這次是「直接執行」:它就是主程式。下方可以改 input() 讀到的身高與體重再跑一次。
在終端機:直接執行與匯入、模組搜尋路徑
同一個資料夾 lab 裡有 bmi.py(上面那份)和 main.py(from bmi import BMI 的主程式)。跟著步驟看看在終端機執行時會發生什麼事。
-
1
直接執行 bmi.py
python 檔名執行的檔案就是主程式,__name__是'__main__',所以會問身高體重。 -
2
執行 main.py,由它匯入 bmi
這次
bmi.py是被匯入的,__name__是'bmi',輸入身高體重的程式不會執行。 -
3
模組搜尋路徑 sys.path
import bmi時,Python 依序在下列位置找bmi.py,找到第一個就停:- 主程式所在的目錄(用
python -c或互動模式時是目前目錄,顯示為空字串) - 環境變數
PYTHONPATH設定的路徑 - 預設路徑:標準函式庫、
site-packages(pip安裝的第三方套件放在這裡)
這些路徑存在
sys模組的path串列裡。下面的路徑只是範例,每台電腦都不同。 - 主程式所在的目錄(用
-
4
找不到模組時
換到上一層目錄再匯入
bmi:搜尋路徑裡沒有bmi.py,就會出現ModuleNotFoundError。解法是回到模組所在的目錄執行,或把模組放在搜尋路徑裡。 -
5
__pycache__ 資料夾
回到原來的目錄,會發現多了
__pycache__:Python 把匯入過的模組編譯成.pyc快取,下次匯入比較快。它是自動產生的,不需要手動管理,也不必放進版本控制。(Windows 的命令提示字元用dir /b代替ls)
想一想:__name__
main.py 裡寫了 import bmi。執行 python main.py 時,bmi.py 裡的 __name__ 是什麼?
下面的程式直接執行時會印出什麼?
def hello():
return "hi"
if __name__ == "__main__":
print(hello(), end=" ")
print("end")
實作:讓 bmi 模組可以自己測試
下面是 bmi 模組。請在檔案最後加上 if __name__ == '__main__': 區塊,在區塊裡呼叫 BMI(67, 175),並用 {:.2f} 印出 175cm, 67kg, BMI=21.88。這樣直接執行時會印出測試結果,被匯入時則不會。
重點精華回顧
- 模組=一個
.py檔,模組名稱就是檔名;裡面可以有函數、類別、變數與可執行的程式。 import 模組用「模組.名稱」存取;import 模組 as 別名簡化名稱;from 模組 import 名稱把名稱直接放進目前的命名空間。from 模組 import *很方便,但同名的名稱會互相覆蓋,要小心使用。- 同一個模組只會載入一次;第一次匯入時,模組最上層的程式會執行一次。
dir(模組)傳回模組內所有名稱的排序串列。- 直接執行時
__name__ == '__main__';被匯入時__name__是模組名稱。用if __name__ == '__main__':放「只在直接執行時才跑」的程式。 - 匯入時依
sys.path的順序搜尋模組:主程式所在目錄、PYTHONPATH、預設路徑。