首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python子进程中的多个输入和输出通信

python子进程中的多个输入和输出通信
EN

Stack Overflow用户
提问于 2015-02-19 20:13:19
回答 4查看 31.7K关注 0票数 29

我需要做一些类似于this post的事情,但是我需要创建一个子进程,它可以被输入并多次输出。那篇文章的公认答案有很好的代码..。

代码语言:javascript
复制
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

...that我想继续这样下去:

代码语言:javascript
复制
grep_stdout2 = p.communicate(input=b'spam\neggs\nfrench fries\nbacon\nspam\nspam\n')[0]
print(grep_stdout2.decode())

# french fries

但是,唉,我得到了以下错误:

代码语言:javascript
复制
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

如果我正确理解,proc.stdin.write()方法不能使您收集输出。什么是最简单的方式来保持行为持续的输入/输出打开?

编辑:====================

看起来,pexpect是一个有用的库,我想要做的事情,但我有困难,使它的工作。以下是对我实际任务的更完整的解释。我正在使用hfst获得单个(俄语)单词的语法分析。下面演示它在bash中的行为:

代码语言:javascript
复制
$ 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

> 

我希望我的脚本能够一次得到一种形式的分析。我尝试过这样的代码,但它不起作用。

代码语言:javascript
复制
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
# 
# 

显然,我误解了pexpect.before所做的事情。我怎样才能得到每个字的输出,每次一个字?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-02-24 08:01:49

这个答案应该归功于@J.F.Sebastian。谢谢你的评论!

下面的代码得到了我预期的行为:

代码语言:javascript
复制
import pexpect

analyzer = pexpect.spawn('hfst-lookup analyser-gt-desc.hfstol', encoding='utf-8')
analyzer.expect('> ')

for word in ['слово', 'сработай']:
    print('Trying', word, '...')
    analyzer.sendline(word)
    analyzer.expect('> ')
    print(analyzer.before)
票数 17
EN

Stack Overflow用户

发布于 2015-02-19 20:33:06

Popen.communicate()是一种帮助方法,它将数据一次性写入stdin,并创建线程从stdoutstderr中提取数据。它在完成数据写入时关闭stdin,并读取stdoutstderr,直到这些管道关闭。您不能执行第二个communicate,因为子程序在返回时已经退出了。

与子进程的交互会话要复杂得多。

一个问题是,儿童进程是否甚至认识到它应该是互动的。在大多数命令行程序用于交互的C库中,从终端(例如linux控制台或"pty“伪终端)运行的程序是交互式的,并且经常刷新它们的输出,但是那些通过管道从其他程序运行的程序是非交互式的,并且很少刷新它们的输出。

另一个问题是如何在没有死锁的情况下读取和处理stdoutstderr。例如,如果您阻止读取stdout,但stderr填充了它的管道,则子程序将停止运行,您将被卡住。您可以使用线程将两个线程都拉到内部缓冲区中。

另一个问题是你如何对待一个意外退出的孩子。

对于诸如linux和OSX这样的"unixy“系统,编写pexpect模块是为了处理交互式子进程的复杂性。对于Windows,我不知道有什么好的工具可以这样做。

票数 30
EN

Stack Overflow用户

发布于 2015-02-19 20:17:20

当您想要向进程发送输入时,请使用proc.stdin.write()。无论何时您想要从进程中获得输出,都可以使用proc.stdout.read()。构造函数的stdinstdout参数都需要设置为PIPE

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28616018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档