Python:迭代标准输出

问题描述

我正在尝试从子流程中获取异常。如果我使用.communicate,我可以得到它,但是我想避免使用它,因为我正在从子流程中流式传输输出,并且不想等到整个子流程完成。还要假设整个子流程可能花费很长时间。想知道如何在从子流程中流式输出stdout时捕获引发的异常。

考虑下面的示例,所以我想让版本1工作,版本2可以工作,但是不要那样。

在main.py

import subprocess


class ExtProcess():
    def __init__(self,*args):
        self.proc = subprocess.Popen(['python',*args],stdout=subprocess.PIPE)

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            line = self.proc.stdout.readline()
            if self.proc.returncode:
                raise Exception("error here")
            if not line:
                raise stopiteration
            return line


def run():
    ## version #1
    reader = ExtProcess("sample_extproc.py")
    for d in reader:
        print(f"got: {d}")

    ## version #2
    # proc = subprocess.Popen(['python',"sample_extproc.py"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    # output,error = proc.communicate()
    # print("got:",output)
    # if proc.returncode:
    #     raise Exception(error)

def main():
    try:
        print("start...")
        run()
        print("complete...")
    except Exception as e:
        print(f"Package midstream error here: {str(e)}")
    finally:
        print("clean up...")


if __name__ == "__main__":
    main()

在sample_extproc.py

for x in range(10):
    print(x)
    if x == 3:
        raise RuntimeError("catch me")

我想从版本1中获得类似以下内容输出

start...
got: b'0\r\n'
got: b'1\r\n'
got: b'2\r\n'
got: b'3\r\n'
Package midstream error here: b'Traceback (most recent call last):\r\n  File "sample_extproc.py",line 4,in <module>\r\n    raise RuntimeError("catch me")\r\nRuntimeError: catch me\r\n'
clean up...

基本上,它会迭代子流程中的stdout,然后在发生异常时打印异常,然后继续执行清理。

解决方法

以下是我对以下问题的答案,它确实基于@CharlesDuffy的评论:

简而言之,请确保stderr=subprocess.PIPE类中有ExtProcess,然后答案在版本3中,在迭代标准输出之后,我们使用.wait()和{{1 }}检查是否存在错误,如果出现错误,则引发异常,从returncode抓取错误以捕获到父/主中。

stderr.read()