ホームページ >バックエンド開発 >Python チュートリアル >サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説
ここでは Windows のシェルを例として使用します:
subprocess *
理解を容易にするために、非常に単純なコードを使用して説明します:
Popen を使用して p をインスタンス化し、サブルーチンを作成していることがわかります。 . cmd.exe に、Stdin (標準入力ストリーム) と Stdout (標準出力ストリーム) を指定します。
は、これらのチャネルが開かれることを示すために使用される特別な値です。 。 (Python3.5 では、操作を改善するために run() メソッドが追加されました)
それでは続きます
この情報に見覚えはありますか?これは cmd の標準出力のすべてです。
すると、次のように出力されます:
先ほど書いたメッセージ「echo Hellwworldsrn」が書き込まれ、成功したようです。
入力バッファをリフレッシュするために p.stdin.flush() を使用することに注意してください。少なくとも Windows システムでは、出力情報にも "rn" が必要です。それ以外の場合は、リフレッシュ (p.stdin .flush) のみが無効になります。
サブルーチン cmd.exe の作成に成功し、「echo Hellwworldsrn」を書き込みました。その後、cmd がそれを取得して実行し、Hellwworlds に戻りました。これは非常に単純な読み取り/書き込み操作です。
簡単に読み書きできるようになったので、for とスレッドを追加しましょう。味が良くなるかもしれません~
#run.py from subprocess import * import threading import time p =Popen('cmd.exe',shell=True,stdin=PIPE,stdout=PIPE) def run(): global p while True: line = p.stdout.readline() if not line: #空则跳出 break print(">>>>>>",line.decode("GBK")) print("look up!!! EXIT ===") #跳出 w =threading.Thread(target=run) p.stdin.write("echo HELLW_WORLD!\r\n".encode("GBK")) p.stdin.flush() time.sleep(1) #延迟是因为等待一下线程就绪 p.stdin.write("exit\r\n".encode("GBK")) p.stdin.flush() w.start()
とても良いですね、出力は何だと思いますか?
改行が多い理由は、cmdが返す結果に改行があり、印刷出力では改行が追加されるため、sys.stdoutの使用を検討できます。 .write を実行して、追加の行が入らないようにします
この場合、基本的な読み取りと書き込みができたら、カプセル化を開始しましょう。
これ以上ナンセンスではありません。本当に学びたい場合は、コードを注意深く読んでください。
110行目
全ての処理を1つのクラスに実装しており、出口フィードバック関数、準備完了フィードバック関数、出力フィードバック関数の3つのパラメータを定義できます。
# -*- coding:utf-8 -*- import subprocess import sys import threading class LoopException(Exception): """循环异常自定义异常,此异常并不代表循环每一次都是非正常退出的""" def __init__(self,msg="LoopException"): self._msg=msg def __str__(self): return self._msg class SwPipe(): """ 与任意子进程通信管道类,可以进行管道交互通信 """ def __init__(self,commande,func,exitfunc,readyfunc=None, shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,code="GBK"): """ commande 命令 func 正确输出反馈函数 exitfunc 异常反馈函数 readyfunc 当管道创建完毕时调用 """ self._thread = threading.Thread(target=self.__run,args=(commande,shell,stdin,stdout,stderr,readyfunc)) self._code = code self._func = func self._exitfunc = exitfunc self._flag = False self._CRFL = "\r\n" def __run(self,commande,shell,stdin,stdout,stderr,readyfunc): """ 私有函数 """ try: self._process = subprocess.Popen( commande, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr ) except OSError as e: self._exitfunc(e) fun = self._process.stdout.readline self._flag = True if readyfunc != None: threading.Thread(target=readyfunc).start() #准备就绪 while True: line = fun() if not line: break try: tmp = line.decode(self._code) except UnicodeDecodeError: tmp = \ self._CRFL + "[PIPE_CODE_ERROR] <Code ERROR: UnicodeDecodeError>\n" + "[PIPE_CODE_ERROR] Now code is: " + self._code + self._CRFL self._func(self,tmp) self._flag = False self._exitfunc(LoopException("While Loop break")) #正常退出 def write(self,msg): if self._flag: #请注意一下这里的换行 self._process.stdin.write((msg + self._CRFL).encode(self._code)) self._process.stdin.flush() #sys.stdin.write(msg)#怎么说呢,无法直接用代码发送指令,只能默认的stdin else: raise LoopException("Shell pipe error from '_flag' not True!") #还未准备好就退出 def start(self): """ 开始线程 """ self._thread.start() def destroy(self): """ 停止并销毁自身 """ process.stdout.close() self._thread.stop() del self if __name__ == '__main__': #那么我们来开始使用它吧 e = None #反馈函数 def event(cls,line):#输出反馈函数 sys.stdout.write(line) def exit(msg):#退出反馈函数 print(msg) def ready():#线程就绪反馈函数 e.write("dir") #执行 e.write("ping www.baidu.com") e.write("echo Hello!World 你好中国!你好世界!") e.write("exit") e = SwPipe("cmd.exe",event,exit,ready) e.start()
出力:
命令が順番に実行されていることがわかります。もちろん、これにはOSも責任を負います。
拡張可能な Pipe クラスが構築されているはずですよね?
A: このコードの前に行番号を追加したのは、ここで何が起こっているのか理解できず、使い方だけは知っているかもしれないため、コピーできないようにするためです。
ちなみに:
すでに詳しく説明されている公式ドキュメントを参照するのが最善です。やりたいことによっては、subprocess.Popen.communicate の方が適している場合があります。
以上がサブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。