如何实现持续互动对话与Python中的子进程? [英] How to Achieve Continuous Interactive Dialog with a Subprocess in Python?
问题描述
也许连续的互动是不正确的短语。我想知道,如果有人可以帮助我了解调用程序从一个Python程序中的子进程的基本知识?我一直在劈砍而去,但我一直运行到令人沮丧的错误。我明白最好用简单的例子。我有一个节目叫square.py保存到我的桌面,使用下面的code:
Maybe continuous interactive isn't the right phrase. I'm wondering if someone could help me understand the basics of calling a program as a subprocess from a Python program? I've been hacking away but I keep running into frustrating errors. I understand best using simple examples. I have a program called square.py saved to my desktop that uses the following code:
i=0
while i<10:
x=int(raw_input('Enter x-dimension: '))
x1 = x*x
print str(x1)
i=i+1
可能有人请向我解释,简单来说如何调用在IDLE这一计划,并保持它持续的互动对话中(保持它的开放和在后台运行),直到它终止自己?
Could someone please explain to me in simple terms how to call this program in IDLE and maintain continuous interactive dialogue with it (keep it open and running in the background) until it terminates on its own?
最后,我将需要使用这些知识来调用一个Python的GUI(使用Tkinter的)C语言编写的遗传算法程序。遗传算法输出值的阵列,用户使用这些值做一些事情,给用户的反馈,这些值的效用。用户的反馈是在0-100的形式。当遗传算法接收输入它的神奇和输出数字另一个数组,这会希望有稍微好一点的效用。所以我想换一个Python GUI围绕一个可怕的期待C程序,喂C程序反馈值和接收数字数组。
Eventually I will need to use this knowledge to call a genetic algorithm program written in C from a Python GUI (using tkinter). The genetic algorithm outputs an array of values, the user uses those values to do something and gives user feedback as to the utility of those values. The user feedback is in the form of 0-100. When the genetic algorithm receives the input it does its magic and outputs another array of numbers, which would hopefully have slightly better utility. So I want to wrap a Python GUI around a scary looking C program, feed the C program a feedback value and receive an array of numbers.
我希望我解释了什么是我想要做的不够好;如果有人能帮助我用的子进程调用square.py,传递给它的值,并取回它的输出,我将pretty的快乐。干杯!
I hope I explained what I'm trying to do well enough; if anyone can help me use subprocess to call square.py, pass it a value and get back its output I would be pretty happy. Cheers!
推荐答案
程序从被设计为与其他程序交互的程序不同。你的 square.py
脚本更接近前一类。可能的问题:
Programs that are designed to interact with a human are different from programs that are designed to interact with other programs. Your square.py
script is closer to the former category. Possible issues:
- 中,迫使一个父脚本一个行的中间的端部提示给读一个字节的时间,而不是实线或已知的块以避免阻塞
- 在孩子的答案是没有明确刷新。这意味着,块缓冲可以在非交互式模式例如启用,当通过
子
没有PTY
运行
- the prompt ends in the middle of a line that forces a parent script to read one byte at a time instead of full lines or known chunks to avoid blocking
- child's answers are not flushed explicitly. It means that the block buffering may be enabled in non-interactive mode e.g., when it is run via
subprocess
withoutpty
下面是如何,你可以使用它在其目前的形式子
模块进行交互:
Here's how you could interact with it using subprocess
module in its current form:
#!/usr/bin/env python
from __future__ import print_function
import sys
from itertools import cycle
from subprocess import Popen, PIPE
from textwrap import dedent
# start child process
p = Popen([sys.executable or 'python', '-u', '-c', dedent("""
for i in range(10):
x = int(input('Enter x-dimension: '))
print(x*x)
""")], stdin=PIPE, stdout=PIPE, universal_newlines=True, bufsize=1)
for n in cycle([3, 1, 4, 15, 926]): # infinite loop
while p.poll() is None: # while the subprocess is running
# send input to the child
print(n, file=p.stdin)
# read & parse answer
data = p.stdout.readline().rpartition(' ')[2]
if not data: # EOF
answer = None
break # exit inner loop
answer = int(data)
if answer == 1: # show example when input depends on output
n += 1
else: # done with given `n`
break # exit inner loop
else: # subprocess ended
break # exit outer loop
if answer is not None:
print("Input %3d Output %6d" % (n, answer))
p.communicate() # close pipes, wait for the child to terminate
这是同样的事情,但使用 pexpect
(比较):
And here's the same thing but using pexpect
(for comparison):
#!/usr/bin/env python
import sys
from itertools import cycle
from textwrap import dedent
import pexpect
child = pexpect.spawnu(sys.executable or 'python', ['-c', dedent("""
for i in range(10):
x = int(input('Enter x-dimension: '))
print(x*x)
""")])
for n in cycle([3, 1, 4, 15, 926]):
while True:
i = child.expect([pexpect.EOF, u'x-dimension:'])
if i == 0: # EOF
answer = None
child.close()
sys.exit()
elif i == 1: # child waits for input
child.sendline(str(n))
child.expect(u'\\n\\d+\\s')
answer = int(child.after)
if answer == 1:
n += 1
else:
break
else:
assert 0
else: # child terminated
break
if answer is not None:
print("Input %3d Output %6d" % (n, answer))
这两个脚本被写入到从同一来源支持的Python 2和Python 3。
Both scripts are written to support Python 2 and Python 3 from the same source.
注:有 -u
在子
基于脚本,让尽快读取行参数因为它们是可用的,即使在非交互模式。 pexpect
基于脚本的工作原理没有这样的开关。 STDIO
为基础的程序可以缓冲/使行缓冲的使用 stdbuf
,无缓冲
实用程序或通过提供PTY 。
Note: there is -u
argument in the subprocess
-based script that allows to read the lines as soon as they are available even in non-interactive mode. pexpect
-based script works without such switch. stdio
-based programs can be unbuffered/make line-buffered using stdbuf
, unbuffer
utilities or by providing a pty.
您可以看到,即使是最简单的孩子脚本( square.py
)需要克服一些问题,甚至在所有的工作。
You can see that even the simplest child script (square.py
) requires to overcome several issues to even work at all.
一切都是简单的,当孩子计划预计将被其他程序,而其余的人类可读(可调试)运行。在这种情况下, square.py
可能是这样的:
Everything is simpler when the child program expects to be run from another program while remaining human-readable (debuggable). In this case, square.py
could look like:
#!/usr/bin/env python
import sys
import time
for line in iter(sys.stdin.readline, ''): # get line as soon as it is available
print(int(line)**2) # find square
sys.stdout.flush() # make the answer available immediately
time.sleep(.5) # a delay to show that the answer is available immediately
可以用它从一个子
基于模块一次全部模式:
It could be used from a subprocess
-based module in "all at once" mode:
import sys
from subprocess import Popen, PIPE
L = [2, 7, 1] # numbers to be squared
p = Popen([sys.executable or 'python', 'square.py'], stdin=PIPE, stdout=PIPE,
universal_newlines=True, bufsize=-1)
answers = map(int, p.communicate("\n".join(map(str, L)))[0].splitlines())
或者一次在一个数:
Or one number at a time:
#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE
answers = []
p = Popen([sys.executable or 'python', 'square.py'], stdin=PIPE, stdout=PIPE,
bufsize=1)
for c in [b'2', b'7', b'1']:
p.stdin.write(c + b'\n')
p.stdin.flush()
answers.append(int(p.stdout.readline()))
print(answers)
p.communicate() # close pipes, wait for child to finish
print(answers)
要获得在C程序中的数组;你可以 JSON
模块:
To get an array from your C program; you could json
module:
import json
from subprocess import Popen, PIPE
p = Popen(['./c-program', 'other', 'args'], stdin=PIPE, stdout=PIPE, bufsize=1)
p.stdin.write(json.dumps({'parameter': 8}).encode() + b'\n') # send input
p.stdin.flush()
result = json.loads(p.stdout.readline().decode()) # e.g., {"result": [0, 0, 7]}
# ...
p.communicate() # close pipes, wait for child to finish
这篇关于如何实现持续互动对话与Python中的子进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!