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()。