我正在运行从其他人那里继承的代码库,该代码库大量使用用户输入。因此,我使用 来运行它subprocess.Popen。以下是示例。以下脚本 ( caller.py) 调用第三方代码。
subprocess.Popen
caller.py
from subprocess import Popen, PIPE, STDOUT import sys user_input = ['John', '555'] communicate_argument = '\n'.join(user_input) p = Popen([sys.executable, 'example2.py'], stdout=PIPE, stdin=PIPE, stderr=STDOUT, encoding='utf-8') stdout, stderr = p.communicate(communicate_argument) print(stdout)
以下脚本(example.py)通过接受来自用户的几个输入参数来模拟我提供的源代码的行为:
example.py
name = input('What is your name\n') age = input('What is your age\n') print('You are {}, and you are {} years old'.format(name, age))
运行代码一切正常,我得到了预期的输出。
调试代码部分有效,但部分无效。调试器成功附加到子进程,p因此放置的任何断点都将起作用。但是,调试控制台example.py似乎没有成功附加到子进程。当我尝试在调试控制台中输入一些变量时,它们不会打印出来,即使它们在我的调试会话中显示为活动变量。
p
你遇到的问题是因为 subprocess.Popen 启动的子进程和主进程之间的输入/输出流被重定向,从而导致调试控制台无法正常附加到子进程。以下是一些方法来调试子进程代码并解决问题。
Pdb
可以在 example.py 中插入 Python 的内置调试器 pdb,如下所示:
pdb
import pdb name = input('What is your name\n') pdb.set_trace() # 设置断点 age = input('What is your age\n') print('You are {}, and you are {} years old'.format(name, age))
这样,在运行 caller.py 时,调试器会启动,你可以通过控制台输入变量查看和调试子进程中的代码。
subprocess.run
stderr
stdout
如果你希望调试更简单,可以用 subprocess.run 替代 Popen,并将子进程的输出直接显示在主进程的终端中。
Popen
修改 caller.py 如下:
from subprocess import run import sys user_input = ['John', '555'] communicate_argument = '\n'.join(user_input) result = run( [sys.executable, 'example2.py'], input=communicate_argument, text=True # 等价于 encoding='utf-8' ) print(result.stdout)
这样,调试器可以正确附加到子进程,并且输出会直接显示在主终端中。
如果你使用的是 IDE(如 PyCharm 或 VS Code),可以配置调试器以附加到子进程:
launch.json
添加以下配置:
json { "name": "Python: Attach to Subprocess", "type": "python", "request": "launch", "program": "caller.py", "console": "integratedTerminal", "subProcess": true }
启动调试器,子进程也会被附加到。
PyCharm:
如果你必须在调试会话中直接控制子进程的输入/输出,可以避免将 stdin 和 stdout 重定向,允许子进程直接与用户交互。
stdin
修改 caller.py:
from subprocess import Popen import sys # 不重定向输入输出 p = Popen([sys.executable, 'example2.py']) p.wait() # 等待子进程完成
这种方法将允许 example2.py 的调试控制台正常工作,但用户输入需要手动提供。
example2.py
选择适合你需求的方法即可。