Múltiples entradas y salidas en subproceso de python se comunican
subprocess stdout (4)
Necesito hacer algo como esta publicación , pero necesito crear un subproceso que pueda recibir entrada y salida muchas veces. La respuesta aceptada de esa publicación tiene un buen código ...
from subprocess import Popen, PIPE, STDOUT
p = Popen([''grep'', ''f''], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
grep_stdout = p.communicate(input=b''one/ntwo/nthree/nfour/nfive/nsix/n'')[0]
print(grep_stdout.decode())
# four
# five
... que me gustaría continuar así:
grep_stdout2 = p.communicate(input=b''spam/neggs/nfrench fries/nbacon/nspam/nspam/n'')[0]
print(grep_stdout2.decode())
# french fries
Pero, por desgracia, me sale el siguiente error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/subprocess.py", line 928, in communicate
raise ValueError("Cannot send input after starting communication")
ValueError: Cannot send input after starting communication
El método proc.stdin.write () no le permite recopilar resultados, si lo entiendo correctamente. ¿Cuál es la forma más sencilla de mantener abiertas las líneas para la entrada / salida en curso?
Editar: ====================
Parece que
pexpect
es una biblioteca útil para lo que estoy tratando de hacer, pero tengo problemas para que funcione.
Aquí hay una explicación más completa de mi tarea real.
Estoy usando
hfst
para obtener análisis gramaticales de palabras individuales (rusas).
Lo siguiente demuestra su comportamiento en un shell bash:
$ hfst-lookup analyser-gt-desc.hfstol
> слово
слово слово+N+Neu+Inan+Sg+Acc 0.000000
слово слово+N+Neu+Inan+Sg+Nom 0.000000
> сработай
сработай сработать+V+Perf+IV+Imp+Sg2 0.000000
сработай сработать+V+Perf+TV+Imp+Sg2 0.000000
>
Quiero que mi script pueda obtener los análisis de un formulario a la vez. Intenté un código como este, pero no funciona.
import pexpect
analyzer = pexpect.spawnu(''hfst-lookup analyser-gt-desc.hfstol'')
for newWord in [''слово'',''сработай''] :
print(''Trying'', newWord, ''...'')
analyzer.expect(''> '')
analyzer.sendline( newWord )
print(analyzer.before)
# trying слово ...
#
# trying сработай ...
# слово
# слово слово+N+Neu+Inan+Sg+Acc 0.000000
# слово слово+N+Neu+Inan+Sg+Nom 0.000000
#
#
Obviamente, he entendido mal lo que
pexpect.before
hace antes.
¿Cómo puedo obtener la salida de cada palabra, una a la vez?
Esta respuesta debe atribuirse a @JFSebastian. ! Gracias por los comentarios!
El siguiente código obtuvo mi comportamiento esperado:
import pexpect
analyzer = pexpect.spawnu(''hfst-lookup analyser-gt-desc.hfstol'')
analyzer.expect(''> '')
for word in [''слово'', ''сработай'']:
print(''Trying'', word, ''...'')
analyzer.sendline(word)
analyzer.expect(''> '')
print(analyzer.before)
HFST tiene enlaces de Python: https://pypi.python.org/pypi/hfst
Usarlos debería evitar todo el problema del vaciado, y le dará una API más limpia para trabajar que analizar el resultado de la cadena de pexpect.
Desde Python REPL, puede obtener algunos documentos sobre los enlaces con
dir(hfst)
help(hfst.HfstTransducer)
o lea https://hfst.github.io/python/3.12.2/QuickStart.html
Arrebatando las partes relevantes de los documentos:
istr = hfst.HfstInputStream(''hfst-lookup analyser-gt-desc.hfstol'')
transducers = []
while not (istr.is_eof()):
transducers.append(istr.read())
istr.close()
print("Read %i transducers in total." % len(transducers))
if len(transducers) == 1:
out = transducers[0].lookup_optimize("слово")
print("got %s" % (out,))
else:
pass # or handle >1 fst in the file, though I''m guessing you don''t use that feature
Siempre que desee enviar información al proceso, use
proc.stdin.write()
.
Siempre que desee obtener resultados del proceso, use
proc.stdout.read()
.
Los argumentos
stdin
y
stdout
para el constructor deben establecerse en
PIPE
.
Popen.communicate()
es un método auxiliar que realiza una escritura única de datos en
stdin
y crea hilos para extraer datos de
stdout
y
stderr
.
Cierra
stdin
cuando termina de escribir datos y lee
stdout
y
stderr
hasta que se cierran esas tuberías.
No puede
communicate
por segunda vez porque el niño ya ha salido cuando regresa.
Una sesión interactiva con un proceso secundario es bastante más complicada.
Un problema es si el proceso secundario incluso reconoce que debería ser interactivo. En las bibliotecas C que la mayoría de los programas de línea de comandos utilizan para la interacción, los programas que se ejecutan desde terminales (por ejemplo, una consola de Linux o un pseudo terminal "pty") son interactivos y eliminan su salida con frecuencia, pero los que se ejecutan desde otros programas a través de PIPES no son interactivo y vaciar su salida con poca frecuencia.
Otra es cómo debe leer y procesar
stdout
y
stderr
sin bloqueo.
Por ejemplo, si bloquea la lectura
stdout
, pero
stderr
llena su tubo, el niño se detendrá y usted estará atascado.
Puede usar subprocesos para colocar ambos en búferes internos.
Otra es cómo lidias con un niño que sale inesperadamente.
Para sistemas "unixy" como Linux y OSX, el módulo
pexpect
está escrito para manejar las complejidades de un proceso secundario interactivo.
Para Windows, no hay una buena herramienta que conozca para hacerlo.