Maison >développement back-end >Tutoriel Python >Explication détaillée de l'utilisation du sous-processus par Python3 pour implémenter les méthodes de communication en lecture/écriture des opérations interactives des tuyaux de pipeline
Nous utilisons ici le shell sous Windows comme exemple :
subprocess *
Pour faciliter votre compréhension, nous utilisons un bout de code très simple pour illustrer :
Vous pouvez voir que nous avons utilisé Popen pour instancier un p, créé le sous-programme cmd.exe, puis nous lui avons donné Stdin (flux d'entrée standard) et Stdout (flux de sortie standard)
l'avons utilisé à ; en même temps subprocess.PIPE comme paramètre, il s'agit d'une valeur spéciale utilisée pour indiquer que ces canaux doivent être ouverts. (Dans Python3.5, la méthode run() a été ajoutée pour de meilleures opérations)
Ensuite, nous continuons avec
ces informations ça vous semble familier ? C'est toute la sortie standard de cmd !
Ensuite, ceci sera affiché :
Le message "echo Hellwworldsrn" que nous venons d'écrire a été écrit, et il semble avoir réussi !
Notez que nous utilisons p.stdin.flush() pour actualiser le tampon d'entrée, et les informations de sortie ont également besoin d'un "rn", au moins dans les systèmes Windows, sinon juste un rafraîchissement. (p.stdin.flush) sera invalide
Nous avons créé avec succès le sous-programme cmd.exe et écrit "echo Hellwworldsrn". Ensuite, cmd l'a obtenu et exécuté, puis est retourné à Hellwworlds. Il s'agit d'une interaction de lecture-écriture très simple !
Maintenant que nous pouvons simplement lire et écrire, ajoutons-en pour et le threading, cela aura peut-être meilleur goût ~
#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()
Très bien Super, devinez quel est le résultat ?
La raison pour laquelle il y a de nombreux sauts de ligne est que les résultats renvoyés par cmd ont des sauts de ligne, puis la sortie d'impression ajoutera un saut de ligne, donc deux lignes sont modifiées . Vous pouvez envisager d'utiliser sys.stdout .write pour la sortie, afin qu'il n'y ait pas de nouvelle ligne supplémentaire
Dans ce cas, vous pouvez effectuer une lecture et une écriture de base, puis commençons l'encapsulation.
Plus de bêtises, allez simplement au code Si vous voulez vraiment apprendre, lisez-le vous-même. Lisez attentivement le code.
Ligne 110
Nous avons implémenté tous les processus dans une seule classe et pouvons définir trois paramètres, un retour de sortie fonction , une fonction de retour prêt et une fonction de retour de sortie.
# -*- 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()
Sortie :
Vous pouvez voir que nos instructions sont exécutées séquentiellement. Bien entendu, le système d’exploitation en est également responsable.
Donc, votre classe Pipe extensible aurait dû être construite, n'est-ce pas ?
A : La raison pour laquelle j'ajoute le numéro de ligne devant ce code est pour vous empêcher de le copier ; car vous ne comprendrez peut-être jamais ce qui se passe ici, mais vous saurez seulement comment l'utiliser.
D'ailleurs :
Il est préférable de se référer aux documents officiels, qui sont déjà expliqués de manière très détaillée. subprocess.Popen.communicate peut vous convenir mieux, selon ce que vous souhaitez faire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!