Python 子进程交互被 stdout.readline() 阻止

Python subprocess interaction blocked by stdout.readline()

我正在尝试使用 subprocess 模块启动另一个 Pyhton 实例,发送命令并检索输出。但是无论我尝试什么,它总是挂在 stdout.readline()。这是我目前的尝试:

from subprocess import Popen, PIPE, STDOUT
script = "import sys;sys.stdout.write('glorp')\n"

p = Popen([r"C:\Program Files\Python37\python.exe",], stdin=PIPE, stdout=PIPE, text=True)
p.stdin.write(script)
print("readline")
print(p.stdout.readline())
print("end")

代码永远不会超过涉及 readline() 的行。我试过在 stdinstdout.

上使用 flush()

这里的主要问题是 Python 解释器在我们作为子进程启动时没有处于交互模式。正如 Python documentation 注释:

When called with standard input connected to a tty device, it prompts for commands and executes them

在这种情况下,子进程的 stdin 没有连接到终端(“tty 设备”)。并且

In non-interactive mode, the entire input is parsed before it is executed.

所以 Python 只是坐在那里什么都不做,直到 stdin 关闭。但是我们可以用 -i command-line option 强制它进入交互模式。那么:

When a script is passed as first argument or the -c option is used, enter interactive mode after executing the script or the command, even when sys.stdin does not appear to be a terminal.

传递 -q option

也很有用

Don’t display the copyright and version messages even in interactive mode.

并通过设置bufsize=0以非缓冲模式与子进程通信。然后我们可以让解释器 运行 多个命令,我们可以检查中间的输出:

from subprocess import Popen, PIPE

p = Popen(['python', '-i', '-q'], stdin=PIPE, stdout=PIPE, text=True, bufsize=0)

p.stdin.write('print("First line executed.")\n')
print(p.stdout.readline(), end='')

p.stdin.write('print("Second line executed.")\n')
print(p.stdout.readline(), end='')

请注意,控制台中的提示 (>>>) 可能出现乱序:

>>> >>> First line executed.
Second line executed.
>>>

我们可以通过在启动解释器时将 '-c', 'import sys; sys.ps1=""' 添加到参数列表来隐藏 V 形符号。

还建议在两端明确设置编码为UTF-8。在 Python 错误跟踪器上的 this issue 中可以找到更详尽的演示。