杰瑞科技汇

python运行时调用python

使用 subprocess 模块 (最推荐)

subprocess 模块是 Python 官方推荐的用于创建和管理子进程的工具,它功能强大,灵活,并且旨在替代旧的 os.systemos.spawn* 等方法。

python运行时调用python-图1
(图片来源网络,侵删)

核心函数

  1. subprocess.run() (Python 3.5+ 推荐) 这是最现代、最通用的接口,它会执行命令,等待它完成,然后返回一个 CompletedProcess 对象。

  2. subprocess.Popen() 这是最底层、最强大的接口,它启动一个进程,但不等待它完成,而是立即返回,你需要手动管理进程的生命周期(等待它结束、读取输出等),当你需要与子进程进行复杂的交互(双向通信)时,这个接口是必需的。


示例 1:使用 subprocess.run() 执行一个独立的 .py 文件

假设我们有两个文件:

main_script.py (调用者)

python运行时调用python-图2
(图片来源网络,侵删)
import subprocess
import sys
print("主脚本开始运行...")
# 定义要执行的子脚本路径
script_to_run = "sub_script.py"
try:
    # 使用 run() 执行子脚本
    # check=True 会在子脚本返回非零退出码(即出错)时抛出 CalledProcessError 异常
    # capture_output=True 会捕获子脚本的 stdout 和 stderr
    result = subprocess.run(
        ["python", script_to_run], 
        check=True, 
        capture_output=True, 
        text=True,  # 将输出解码为文本
        encoding='utf-8' # 指定编码
    )
    # 子脚本执行成功后,获取其输出
    print("\n--- 子脚本执行成功 ---")
    print(f"返回码: {result.returncode}")
    print(f"标准输出: \n{result.stdout}")
    # print(f"标准错误: \n{result.stderr}") # 如果子脚本有错误输出,可以在这里查看
except subprocess.CalledProcessError as e:
    # 如果子脚本执行失败(返回码非零)
    print(f"\n--- 子脚本执行失败 ---")
    print(f"返回码: {e.returncode}")
    print(f"标准输出: \n{e.stdout}")
    print(f"标准错误: \n{e.stderr}")
print("\n主脚本运行结束。")

sub_script.py (被调用者)

import time
import sys
print("子脚本开始运行...")
print("正在执行一些任务...")
time.sleep(2) # 模拟耗时操作
# 从命令行参数中获取信息(可选)
if len(sys.argv) > 1:
    print(f"从主脚本收到的参数: {sys.argv[1]}")
# 故意制造一个错误来测试
# print("这是一个错误信息", file=sys.stderr)
# sys.exit(1) # 以非零状态码退出,表示失败
print("子脚本运行成功,准备退出。")
sys.exit(0) # 以零状态码退出,表示成功

如何运行:

  1. main_script.pysub_script.py 放在同一个目录下。
  2. 在终端中运行:python main_script.py

输出:

主脚本开始运行...
--- 子脚本执行成功 ---
返回码: 0
标准输出: 
子脚本开始运行...
正在执行一些任务...
子脚本运行成功,准备退出。
主脚本运行结束。

示例 2:向子脚本传递参数

只需要在 run() 的列表中添加参数即可。

python运行时调用python-图3
(图片来源网络,侵删)

修改 main_script.py

# ... (前面的代码不变)
try:
    # 向子脚本传递一个参数 "hello world"
    result = subprocess.run(
        ["python", script_to_run, "hello world"], 
        check=True, 
        capture_output=True, 
        text=True
    )
    # ... (后面的代码不变)

运行 sub_script.py 的输出会变为:

子脚本开始运行...
正在执行一些任务...
从主脚本收到的参数: hello world
子脚本运行成功,准备退出。

示例 3:使用 subprocess.Popen() 进行交互

当你需要长时间运行一个进程,或者需要与它进行实时通信时,Popen 是最佳选择。

interactive_main.py

import subprocess
import sys
print("主脚本:使用 Popen 启动一个交互式子进程。")
# 启动子进程,不等待
# stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE 用于管道通信
proc = subprocess.Popen(
    ["python", "interactive_sub_script.py"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    encoding='utf-8'
)
# 向子进程发送输入
print("主脚本:向子进程发送 'greet'")
proc.stdin.write("greet\n")
proc.stdin.flush() # 确保数据被发送
# 读取子进程的输出
output, errors = proc.communicate(timeout=5) # communicate 会读取所有输出并等待进程结束
print(f"主脚本:收到子进程输出 -> {output.strip()}")
if errors:
    print(f"主脚本:收到子进程错误 -> {errors.strip()}")
print(f"主脚本:子进程的最终返回码是 {proc.returncode}")

interactive_sub_script.py

import sys
import time
print("子脚本:我已启动,等待指令...")
# 循环读取来自主进程的输入
for line in sys.stdin:
    command = line.strip()
    print(f"子脚本:收到指令 '{command}'")
    if command == "greet":
        print("子脚本:你好,主进程!")
    elif command == "exit":
        print("子脚本:正在退出...")
        break
    else:
        print("子脚本:未知指令")
    sys.stdout.flush() # 确保输出被发送
print("子脚本:运行结束。")
sys.exit(0)

使用 import 语句 (在同一个程序内)

如果你的代码逻辑上是一个整体,只是想拆分成不同的模块来组织,那么应该使用 import

module_a.py

def function_a():
    print("模块 A 的函数被调用了")
    return 42

main_module.py

# 导入整个模块
import module_a
# 现在可以调用模块中的函数
result = module_a.function_a()
print(f"从模块 A 得到的返回值是: {result}")
# 也可以导入特定函数
# from module_a import function_a
# result = function_a()

关键区别:

  • import:在同一个 Python 解释器进程内运行,两个模块共享全局变量(除非使用 multiprocessing)。
  • subprocess:创建一个全新的、独立的 Python 解释器进程,它有自己的内存空间和全局变量,与父进程完全隔离。

使用 os.system() (不推荐,仅作了解)

这是最老式的方法,简单但功能有限,不推荐在新代码中使用。

import os
print("主脚本开始运行...")
# 返回的是命令执行后的退出码,而不是输出
return_code = os.system("python sub_script.py")
print(f"子脚本执行完毕,退出码: {return_code}")
print("主脚本运行结束。")

缺点:

  • 无法直接获取子脚本的输出(除非重定向到文件)。
  • 不够灵活,错误处理能力差。
  • 安全性较低,如果参数来自用户,容易产生命令注入漏洞。

总结与最佳实践

方法 优点 缺点 适用场景
subprocess.run() 现代、安全、灵活、功能强大、能轻松获取返回码和输出。 相比 os.system 稍显复杂。 绝大多数情况下的首选,执行独立脚本、传递参数、获取结果。
subprocess.Popen() 功能最强大、支持异步、复杂交互(双向通信)。 API 最复杂,需要手动管理进程。 需要与子进程进行实时交互、长时间运行的后台任务。
import 简单、高效、共享内存和状态。 代码必须在同一个程序内,逻辑耦合。 将代码组织成模块和函数,逻辑上属于一个整体的应用。
os.system() 极其简单,一行代码即可。 功能弱、不安全、无法获取输出。 快速执行一个简单的命令,不关心结果,仅用于兼容旧代码。

最终建议:

  1. 如果只是想运行另一个独立的 .py 文件,并获取其执行结果或输出,请使用 subprocess.run()
  2. 如果你的代码逻辑上是一个整体,只是想拆分文件,请使用 import
  3. 如果你需要与一个子进程进行复杂的、实时的交互,请使用 subprocess.Popen()
  4. 避免使用 os.system(),除非你正在维护一个非常古老的代码库。
分享:
扫描分享到社交APP
上一篇
下一篇