如何实现持续互动对话与Python中的子进程? [英] How to Achieve Continuous Interactive Dialog with a Subprocess in Python?

查看:204
本文介绍了如何实现持续互动对话与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 without pty

下面是如何,你可以使用它在其目前的形式模块进行交互:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆