HOWTO · Python
Python 執行另一個 Python 指令碼
本教程演示如何在另一個 Python 指令碼中執行 Python 指令碼
本頁內容
若要在同一個 Python 程序中重用程式碼,請將程式碼放入模組並匯入。若要獨立執行另一個指令碼,請使用 subprocess 啟動子程序。需要呼叫函式或共用物件時,選擇前者;若指令碼應保有自己的程序與命令列行為,則選擇後者。
使用 import 陳述式在另一個 Python 指令碼中執行 Python 指令碼
Python 首次載入模組時,會執行一次該模組最外層的陳述式。請將可重用的工作放在函式中,並將直接執行時才要執行的行為放在 if __name__ == "__main__": 區塊內,避免其他模組匯入此檔案時也觸發這些行為。匯入時使用模組名稱,不要加上 .py 副檔名。
以下是自足的範例:它會在暫存目錄中建立模組、匯入模組,並呼叫其中的函式。範例輸出維持原樣,顯示的文字是英文:
import importlib
import sys
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as folder:
module_path = Path(folder) / "helper_script.py"
module_path.write_text(
'def greet():\n'
' print("Hello from the helper")\n',
encoding="utf-8",
)
sys.path.insert(0, folder)
try:
helper_script = importlib.import_module("helper_script")
helper_script.greet()
finally:
sys.path.remove(folder)
sys.modules.pop("helper_script", None)
Hello from the helper
在專案中,請將輔助模組放在呼叫端旁邊,或放入可匯入的套件。函式與 __main__ 區塊以外的陳述式仍會在匯入時執行,因此模組最外層的工作應限於定義,以及執行一次也安全的初始化。
使用 execfile() 函式在另一個 Python 指令碼中執行 Python 指令碼
execfile() 是一個舊式函式,會在目前的直譯器中執行檔案內的程式碼。舊程式碼中可能會看到它,但並非所有 Python 環境都提供此函式。請將它視為相容性問題,並在使用前確認專案採用的直譯器。基本用法是 execfile("other_script.py")。
Python 的 exec() 可以在指定的命名空間中執行原始碼文字,但不能直接取代 execfile() 來執行檔案。讀取檔案並將內容傳給 exec() 會改變命名空間行為,也不會隔離程序。執行不受信任的程式碼可能會執行任意 Python 程式碼;若要重用程式碼,請優先匯入模組,若要使用獨立程序,則請使用 subprocess。
使用 subprocess 模組在另一個 Python 指令碼中執行 Python 指令碼
若要以子程序執行另一個指令碼,請使用 subprocess.run()。將引數以清單傳入,並使用 sys.executable 指定與呼叫端相同的 Python 直譯器。以下範例會建立並啟動一個小型子指令碼,接著檢查其傳回狀態並印出擷取到的輸出:
import subprocess
import sys
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as folder:
script_path = Path(folder) / "child.py"
script_path.write_text('print("Child process ran")\n', encoding="utf-8")
result = subprocess.run(
[sys.executable, str(script_path)],
check=True,
capture_output=True,
text=True,
)
print(result.stdout, end="")
Child process ran
請將指令碼路徑作為引數傳入;如果子程序需要特定工作目錄,請使用絕對路徑或設定 cwd。子程序執行失敗時,check=True 會引發 CalledProcessError;若呼叫端需要自行處理狀態,請省略此參數並檢查 returncode。使用 capture_output=True 可讀取 stdout 與 stderr,而不將它們直接輸出到終端機。
使用 os.system() 函式在另一個 Python 指令碼中執行 Python 指令碼
os.system() 會將命令字串交給作業系統的 shell,並傳回狀態值。shell 會剖析該字串,因此引號處理與平台差異都不容易管理。請勿串接不受信任的輸入來組成命令:shell 中繼字元可能改變實際執行的內容。撰寫新程式碼時,請優先使用帶有引數清單的 subprocess.run(),以便更清楚地處理狀態,並視需要擷取輸出。只有在維護原本就依賴 shell 命令的簡單舊程式碼時,才主要使用 os.system()。
使用 importlib 模組在另一個 Python 指令碼中執行 Python 指令碼
若可匯入的模組名稱要在執行期間才決定,請使用 importlib.import_module()。它會將模組匯入目前的程序,不會以獨立程序啟動任意檔案。該模組必須能在 Python 的匯入路徑中找到,而且首次匯入時會執行其最外層陳述式。
以下範例會建立可匯入的模組、動態選擇其名稱,並呼叫其中的函式:
import importlib
import sys
import tempfile
from pathlib import Path
with tempfile.TemporaryDirectory() as folder:
module_path = Path(folder) / "task_module.py"
module_path.write_text(
'def run_task():\n'
' print("Task completed")\n',
encoding="utf-8",
)
sys.path.insert(0, folder)
try:
module_name = "task_module"
task_module = importlib.import_module(module_name)
task_module.run_task()
finally:
sys.path.remove(folder)
sys.modules.pop("task_module", None)
Task completed
如果模組名稱固定,一般的 import 寫法更簡單。只有在名稱確實取決於執行期間的設定時,才使用 importlib;並請確認該設定只會選取應用程式允許載入的模組。
結論
若要在目前的程序中重用函式與資料,請使用 import;若要獨立執行另一個指令碼,請使用 subprocess。importlib 可依模組名稱動態匯入。閱讀舊程式碼時可能會遇到舊式函式 execfile();os.system() 則會呼叫 shell,對程序的控制有限。撰寫新的獨立程序程式碼時,請優先使用搭配 sys.executable 與引數清單的 subprocess.run()。