【问题标题】:Open a python process using python's subprocess module使用 python 的 subprocess 模块打开一个 python 进程
【发布时间】:2015-10-07 09:38:09
【问题描述】:

我正在尝试与 python 脚本中的不同 python 解释器进行通信。我写了一个对象,它应该存储子进程并读/写它的标准输入、标准输出、标准错误。

import subprocess
import fcntl
import os

class Python:

    def __init__(self):
        self.process = subprocess.Popen("python", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        fcntl.fcntl(self.process.stdout, fcntl.F_SETFL, os.O_RDONLY | os.O_NONBLOCK)
        fcntl.fcntl(self.process.stderr, fcntl.F_SETFL, os.O_RDONLY | os.O_NONBLOCK)

    def read(self):
        stdout = self.process.stdout.read()
        if stdout:
            print("stdout:", stdout)
        stderr = self.process.stderr.read()
        if stderr:
            print("stderr:", stderr)

    def exec(self, line):
        self.process.stdin.write(bytes((line + "\n").encode("ascii")))
        self.process.stdin.flush()

在 init 函数中创建子进程并将 stdout、stderr 设置为非阻塞模式。 read 函数现在只是将 stdout、stderr 打印到屏幕上,而 exec 函数将一行写入 python 的 stdin 并刷新它。我使用一个简单的 echo 脚本对此进行了测试:

while True:
    print(input())

我能够使用我的 exec 方法,过了一会儿,我使用 read 方法读取了我传递给 exec 方法的行。

我的问题是这不适用于 python 解释器。我试图将所有内容写入其标准输入,但它没有向标准输出、标准错误写入任何内容。

【问题讨论】:

  • 您的代码未启动 IDLE。 Barepython 启动 Python 解释器。要启动 IDLE,您将运行 python3 -midlelib 或类似的。 IDLE 是一个 GUI 程序,可能没有可用的标准输入、标准输出、标准错误。
  • @J.F.Sebastian 对不起,我的错。我的意思是交互式 python 解释器。
  • 这是一个块缓冲问题。传递-u 参数,禁用缓冲。注意:非阻塞 I/O 在这种情况下无济于事,您可以放弃 fcntl 调用。

标签: python subprocess stdout stdin stderr


【解决方案1】:

好吧,我做了一些测试,您的代码按我的预期工作。这意味着您正确地创建了一个 python 解释器并将命令传递给它,并且解释器正确地执行它们。

问题是管道的输出可能会被缓冲(并且在这里)。如果你写了几个 KB,你可以得到开始部分,但是在这里,在 Python 解释器退出之前,实际上没有任何东西写入管道。

确认方式:

p = Python()
p.exec("print('foo')")
p.exec("print('bar')")
p.process.stdin.close() # force interpreter to exit ...
time.sleep(0.1) # wait for the interpreter to exit ...
p.read()

然后你应该得到stdout: b'foo\r\nbar\r\n'


正如 JFSebastian 在其评论中所建议的那样,不被缓冲所困扰的最直接的方法是简单地要求解释器不要缓冲任何东西,无论是使用 -u 选项还是使用 PYTHONUNBUFFERED 环境变量:

class Python:

    def __init__(self):
        self.process = subprocess.Popen("python -u", stdin=subprocess.PIPE,
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE)
        ...

【讨论】:

  • 没错,它的工作原理是这样的。但这对我来说没用,因为我想使用解释器交互。
猜你喜欢
  • 2020-10-12
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多