Python 监控流类

Python 监控流类,python,stream,Python,Stream,我试图创建一个流对象,它在任何时候向其写入数据时都会触发回调函数 class MonitoredStream(): def __init__(self, outstream, callback): self.outstream = outstream self.callback = callback def write(self, s): self.callback(s) self.outstream.write(

我试图创建一个流对象,它在任何时候向其写入数据时都会触发回调函数

class MonitoredStream():
    def __init__(self, outstream, callback):
        self.outstream = outstream
        self.callback = callback

    def write(self, s):
        self.callback(s)
        self.outstream.write(s)

    def __getattr__(self, attr):
        return getattr(self.outstream, attr)
当我直接调用write方法时,这很好,但是当我将子流程的输出连接到流时,我希望它也能工作。例如:

def f(s):
    print("Write")

p = sub.Popen(["sh", "test.sh"], stdout=MonitoredStream(sys.stdout, f))
p.communicate()

这只是将输出直接发送到sys.stdout,完全绕过write函数。还有什么方法可以监视这个输出吗?

我认为这里的问题是
子流程。Popen
不使用管道的Python接口,而是获取文件描述符,然后使用它直接写入管道,正如您给出的
stdout
管道的属性一样,这意味着它使用它,绕过你的代码

我最好的解决办法是在中间设置一个新的管道,让你自己处理这条小溪。我将作为上下文管理器来实现这一点:

import sys
import os
from subprocess import Popen
from contextlib import contextmanager

@contextmanager
def monitor(stream, callback):
    read, write = os.pipe()
    yield write
    os.close(write)
    with os.fdopen(read) as f:
        for line in f:
            callback(line)
            stream.write(line)

def f(s):
    print("Write")

with monitor(sys.stdout, f) as stream:
    p = Popen(["ls"], stdout=stream)
    p.communicate()
当然,尽管您仍然可以使用类:

import sys
import os
from subprocess import Popen

class MonitoredStream():
    def __init__(self, stream, callback):
        self.stream = stream
        self.callback = callback
        self._read, self._write = os.pipe()

    def fileno(self):
        return self._write

    def process(self):
        os.close(self._write)
        with os.fdopen(self._read) as f:
            for line in f:
                self.callback(line)
                self.stream.write(line)

def f(s):
    print("Write")

stream = MonitoredStream(sys.stdout, f)
p = Popen(["ls"], stdout=stream)
p.communicate()
print(stream.process())

虽然我觉得这不太优雅。

这些都是好主意,但如果我理解正确,它们都会等到流关闭后,再将回调函数应用于整个输出。理想情况下,我希望在流中有行可读取时应用回调函数。这是真的,尽管据我所知,
subprocess.communicate()
已经这样做了,所以这应该不是问题。哦,我明白了。如果是这样的话,我将不得不找到另一种方法。我的用例是,我有一个长时间运行的进程,该进程生成日志输出,我希望能够监控输出,并实时做出反应(在进程完成之前)。我只是将输出设置为
subprocess.PIPE
并逐行读取,而不是使用
subprocess.communicate()