杰瑞科技汇

python3调用python2进程

Python 3 脚本不直接执行 Python 2 代码,而是像操作系统一样,启动一个新的、独立的进程去运行那个 Python 2 脚本。

python3调用python2进程-图1
(图片来源网络,侵删)

Python 3 的 subprocess 模块是实现这一目标的最佳工具,下面我将从简单到复杂,详细介绍几种方法,并讨论它们的优缺点和适用场景。


准备工作:创建一个 Python 2 脚本

为了演示,我们先创建一个简单的 Python 2 脚本,py2_script.py

py2_script.py

# -*- coding: utf-8 -*-
import sys
print "--- Python 2 Script Started ---"
print "Python version:", sys.version
print "Arguments received:", sys.argv
# 模拟一个耗时任务
import time
time.sleep(2)
# 从命令行参数中获取一个名字,并打印问候语
if len(sys.argv) > 1:
    name = sys.argv[1]
    print "Hello, %s! (from Python 2)" % name
else:
    print "Hello, World! (from Python 2)"
print "--- Python 2 Script Finished ---"

我们将在 Python 3 脚本中调用这个 py2_script.py

python3调用python2进程-图2
(图片来源网络,侵删)

使用 subprocess.run() (推荐,Python 3.5+)

subprocess.run() 是现代 Python (3.5+) 中推荐的、最简单、最安全的方式,它提供了一个统一的接口来运行命令并等待其完成。

基本调用(无参数)

py3_main.py

import subprocess
# 1. 定义要执行的命令
#    ['python2', 'py2_script.py'] 是一个列表,表示要运行的命令及其参数
#    这比使用字符串 "python2 py2_script.py" 更安全,可以避免shell注入攻击
command = ['python2', 'py2_script.py']
# 2. 运行命令
#    check=True: 如果进程返回非零退出码(表示出错),会抛出 CalledProcessError 异常
#    capture_output=True: 捕获标准输出和标准错误
#    text=True: 将输出解码为文本(而不是字节),默认使用系统编码
try:
    print("--- Python 3: Calling Python 2 script ---")
    result = subprocess.run(command, check=True, capture_output=True, text=True, encoding='utf-8')
    # 3. 处理结果
    print("\n--- Python 2 Script Output ---")
    print(result.stdout) # 打印标准输出
    print("\n--- Python 3: Call Successful ---")
    print("Return code:", result.returncode)
except subprocess.CalledProcessError as e:
    print("\n--- Python 3: Error occurred ---")
    print("Return code:", e.returncode)
    print("Error output:", e.stderr)

运行结果:

--- Python 3: Calling Python 2 script ---
--- Python 2 Script Output ---
--- Python 2 Script Started ---
Python version: 2.7.18 (default, Oct 21 2025, 16:48:29)
[GCC 10.2.1 20250110]
Arguments received: ['py2_script.py']
Hello, World! (from Python 2)
--- Python 2 Script Finished ---
--- Python 3: Call Successful ---
Return code: 0

传递参数

调用时,只需将参数添加到命令列表中即可。

python3调用python2进程-图3
(图片来源网络,侵删)

py3_main_with_args.py

import subprocess
command = ['python2', 'py2_script.py', 'Alice']
# 注意:参数 'Alice' 直接作为列表的元素添加
try:
    print("--- Python 3: Calling Python 2 script with arguments ---")
    result = subprocess.run(command, check=True, capture_output=True, text=True, encoding='utf-8')
    print("\n--- Python 2 Script Output ---")
    print(result.stdout)
except subprocess.CalledProcessError as e:
    print("\n--- Python 3: Error occurred ---")
    print("Error output:", e.stderr)

运行结果:

--- Python 3: Calling Python 2 script with arguments ---
--- Python 2 Script Output ---
--- Python 2 Script Started ---
Python version: 2.7.18 (default, Oct 21 2025, 16:48:29)
[GCC 10.2.1 20250110]
Arguments received: ['py2_script.py', 'Alice']
Hello, Alice! (from Python 2)
--- Python 2 Script Finished ---

使用 subprocess.Popen() (更灵活,适用于复杂交互)

Popen (process open) 是一个更底层的接口,它不会等待子进程结束,而是立即返回一个 Popen 对象,这对于需要与子进程进行持续交互(发送输入、实时读取输出)或并发运行多个进程的场景非常有用。

示例:运行并等待,获取输出

py3_main_popen.py

import subprocess
import time
command = ['python2', 'py2_script.py', 'Bob']
print("--- Python 3: Starting Python 2 script with Popen ---")
# Popen 不会等待,立即返回一个 Popen 对象
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding='utf-8')
# 你可以在这里做其他事情,而不是立即等待
print("Python 3 script is doing other work...")
time.sleep(1)
# 使用 communicate() 方法来等待进程结束,并获取所有输出
# communicate() 会正确处理管道,避免死锁
print("\nPython 3 is now waiting for the Python 2 script to finish...")
stdout, stderr = process.communicate()
if process.returncode == 0:
    print("\n--- Python 2 Script Output ---")
    print(stdout)
else:
    print("\n--- Python 3: Error occurred ---")
    print("Return code:", process.returncode)
    print("Error output:", stderr)

示例:实时读取输出

这是一个 Popen 的强大功能,可以逐行或实时地获取子进程的输出。

py3_main_popen_realtime.py

import subprocess
import time
command = ['python2', 'py2_script.py', 'Charlie']
print("--- Python 3: Starting Python 2 script with Popen (real-time output) ---")
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8')
# 将 stdout 和 stderr合并,然后逐行读取
# iter(process.stdout.readline, '') 会一直读取直到遇到空字符串(进程结束)
for line in iter(process.stdout.readline, ''):
    print("PY2 > ", line.strip()) # .strip() 去除末尾的换行符
# 确保进程已经结束
process.wait()
print("\n--- Python 3: Python 2 script finished with return code", process.returncode, "---")

使用 os.system() (简单但过时)

os.system() 是最简单的方法,但它功能有限,不推荐在新代码中使用,它只是简单地执行命令,并将输出直接打印到你的控制台,你无法捕获输出或检查返回码(除非手动检查)。

py3_main_os_system.py

import os
command = "python2 py2_script.py David"
print("--- Python 3: Calling os.system() ---")
# 返回码是 shell 的返回码,而不是 Python 2 脚本的直接返回码
return_code = os.system(command)
print("\n--- Python 3: os.system() finished with return code", return_code, "---")

为什么不推荐?

  • 无法捕获输出:所有输出都直接显示在终端。
  • 安全性差:如果命令来自用户输入,容易受到 shell 注入攻击。
  • 功能有限:无法进行复杂的交互或错误处理。

关键注意事项和最佳实践

  1. 如何指定 python2 可执行文件?

    • 直接使用 'python2' 假设它在你的系统 PATH 环境变量中,这是最常见的情况。

    • python2 不在 PATH 中,或者你想使用特定的版本,请提供其完整路径:

      # Linux/macOS
      command = ['/usr/bin/python2', 'py2_script.py']
      # Windows
      command = ['C:\\Python27\\python.exe', 'py2_script.py']
  2. 数据交换(进程间通信)

    • 命令行参数:适合传递简单的、少量的数据(如文件名、用户名),数据量有限,且需要小心处理特殊字符(如空格、引号)。
    • 标准输入/输出/错误subprocess 模块通过 stdin, stdout, stderr 参数完美支持。process.communicate() 是处理输入输出的安全方式。
    • 文件:最可靠、最简单的方式,让 Python 2 脚本将结果写入一个文件,Python 3 脚本再从该文件中读取,对于大数据量尤其适用。
    • 网络套接字:如果两个脚本在同一台机器上运行,可以让它们监听和连接本地端口进行通信。
    • 临时文件:使用 tempfile 模块创建临时文件进行数据交换,并在使用后自动删除。
  3. 编码问题

    • Python 2 和 Python 3 在字符串处理上有根本不同,Python 2 的 str 是字节,而 Python 3 的 str 是 Unicode。
    • 当使用 subprocess 时,务必通过 text=True (或 universal_newlines=True) 和 encoding='utf-8' 参数来明确指定文本的编码,这样可以确保字符串在两个进程之间正确传递和转换,避免 UnicodeDecodeErrorUnicodeEncodeError
  4. 错误处理

    • 始终检查子进程的返回码。subprocess.runcheck=True 会自动帮你检查。
    • 捕获 subprocess.CalledProcessError 异常来处理执行失败的情况。
    • 捕获 FileNotFoundError 异常,以防 python2 命令或脚本文件不存在。
方法 优点 缺点 推荐场景
subprocess.run() 简单、安全、推荐、功能全面、处理错误和输出方便 需要 Python 3.5+ 绝大多数情况下的首选
subprocess.Popen() 非常灵活、可并发、可实时交互、可进行复杂进程控制 代码稍复杂,需要手动管理进程 需要与子进程持续交互、并发运行、或获取实时输出时。
os.system() 极其简单,一行代码即可 功能弱、不安全、无法捕获输出、不推荐用于生产 快速测试、一次性脚本,不关心输出和错误时。

对于在 Python 3 中调用 Python 2 进程,强烈建议你从 subprocess.run() 开始,它提供了最佳的性能、安全性和易用性组合,如果发现 run() 无法满足你的需求(例如需要实时输出),再考虑使用 Popen

分享:
扫描分享到社交APP
上一篇
下一篇