subprocess.run() 是串行执行 Python 脚本的最稳方式,它阻塞等待前一个完成再启动下一个,比 os.system() 安全、比 subprocess.Popen() 简单,需用绝对路径或指定 cwd,显式检查 returncode,推荐搭配 capture_output=True 和 text=True 使用。

用 subprocess.run() 串行执行最稳
Python 脚本顺序执行,subprocess.run() 是默认推荐方式——它会阻塞等待前一个脚本退出后再启动下一个,天然保证顺序。比 os.system() 安全(不走 shell 解析),比 subprocess.Popen() 简单(不用手动 .wait())。
常见错误是误用 subprocess.Popen() 后没调 .wait(),结果脚本并行跑起来,输出错乱、文件冲突、状态判断失效。
- 每个脚本路径必须写绝对路径,或确保当前工作目录(
cwd=...)正确,否则FileNotFoundError - 显式检查返回码:
if result.returncode != 0:,别默认“跑完就成功” - 加
capture_output=True, text=True方便捕获和调试 stdout/stderr
import subprocess
scripts = ["script1.py", "script2.py", "cleanup.py"]
for script in scripts:
result = subprocess.run(["python", script], capture_output=True, text=True)
if result.returncode != 0:
print(f"{script} failed:", result.stderr)
break
需要传参或环境隔离?用 subprocess.run() + env
多个脚本之间可能依赖不同 Python 版本、包版本或环境变量(比如 ENV=prod),直接在同一个解释器里 import 执行会污染状态;用 subprocess 启新进程,天然隔离。
容易踩的坑是复用父进程的 os.environ:比如父进程设置了 DEBUG=1,但第二个脚本不该看到它——得显式构造干净的 env 字典。
立即学习“Python免费学习笔记(深入)”;
- 用
os.environ.copy()再修改,避免意外继承敏感变量(如PATH、HOME) - 参数带空格或特殊字符?统一用列表传参,别拼字符串,防止 shell 注入或解析错误
- Windows 下注意
python命令可能叫python.exe,建议用sys.executable替代硬编码
import subprocess, os, sys env = os.environ.copy() env["LOG_LEVEL"] = "WARN" subprocess.run([sys.executable, "step2.py", "--mode", "fast"], env=env)
脚本失败要中断?别靠 try/except 包整个循环
顺序执行的核心诉求是“前一个挂了,后面的别跑”。很多人用 try/except 包住 subprocess.run(),但漏掉关键点:异常只捕获 Python 层面的错误(比如文件不存在),而脚本本身 exit(1) 是正常退出,returncode 非零才是业务失败信号。
更隐蔽的问题是:某些脚本内部用了 sys.exit(0) 表示“跳过”,但你期望它失败时中断——这时得提前约定好退出码语义,不能只看是否抛异常。
-
subprocess.run(...).check_returncode()可以自动 raiseCalledProcessError,比手动 if 更简洁 - 如果某个脚本允许失败继续(比如清理步骤),单独处理它的
returncode,别一刀切 break - 日志里记清是“脚本崩溃”(异常)还是“脚本报错”(非零码),排查路径完全不同
要不要用 concurrent.futures 或 Celery?先问是不是真需要
看到“多个脚本”,有人立刻想上并发框架。但顺序执行场景下,并发反而引入复杂度:状态同步、错误传播、日志交叉、资源争抢(比如都写同一个临时文件)。
Celery 适合长期运行、可重试、有队列调度需求的任务;concurrent.futures 适合 CPU/IO 并行计算——这两者和“按顺序一个接一个跑完再下一个”是不同问题域。
- 如果只是部署流水线、本地数据预处理、CI 中的步骤链,老老实实用 for 循环 +
subprocess.run() - 只有当某一步耗时极长(>5 分钟)、且后续步骤不依赖其输出时,才考虑拆成异步+回调,但那就不是“顺序执行”了
- 用 Makefile 或
nox也能做顺序编排,但 Python 脚本内控更灵活(比如动态决定下一步跑哪个)



















