2

データが書き込まれるたびにコールバック関数をトリガーするストリーム オブジェクトを作成しようとしています。

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)

これは、書き込みメソッドを直接呼び出すと正常に機能しますが、サブプロセスの出力をストリームにフックしている場合にも機能するようにしたいと考えています。例えば:

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

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

これは、出力を sys.stdout に直接送信し、書き込み関数を完全にバイパスします。この出力も監視できる方法はありますか?

4

1 に答える 1

2

ここでの問題はsubprocess.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())

これはエレガントではないと思いますが。

于 2012-06-08T19:15:59.123 に答える