1

継続的なインタラクティブという表現は適切ではないかもしれません。プログラムをPythonプログラムからサブプロセスとして呼び出す基本を誰かが理解するのを手伝ってくれるかどうか疑問に思っていますか? 私はハッキングしてきましたが、イライラするエラーに遭遇し続けています。簡単な例を使用して最もよく理解できます。次のコードを使用するデスクトップに保存された square.py というプログラムがあります。

i=0
while i<10:
    x=int(raw_input('Enter x-dimension: '))
    x1 = x*x
    print str(x1)
    i=i+1

このプログラムを IDLE で呼び出し、プログラムが自然に終了するまで継続的なインタラクティブな対話を維持する (バックグラウンドで開いて実行し続ける) 方法を簡単な言葉で説明してもらえますか?

最終的には、この知識を使用して、C で記述された遺伝的アルゴリズム プログラムを Python GUI から (tkinter を使用して) 呼び出す必要があります。遺伝的アルゴリズムは値の配列を出力し、ユーザーはそれらの値を使用して何かを行い、それらの値の有用性についてユーザーにフィードバックを提供します。ユーザー フィードバックは 0 ~ 100 の形式です。遺伝的アルゴリズムが入力を受け取ると、魔法のように別の数値の配列を出力します。だから私は恐ろしい見た目の C プログラムに Python GUI をラップし、C プログラムにフィードバック値を送り、数値の配列を受け取りたいと思っています。

私がやろうとしていることを十分に説明できれば幸いです。subprocess を使用して square.py を呼び出し、それに値を渡してその出力を取得するのを手伝ってくれる人がいれば、私はとても幸せです。乾杯!

4

2 に答える 2

2

人間と対話するように設計されたプログラムは、他のプログラムと対話するように設計されたプログラムとは異なります。あなたのsquare.pyスクリプトは前者のカテゴリに近いです。考えられる問題:

subprocess現在の形式でモジュールを使用して対話する方法は次のとおりです。

#!/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(比較のために)使用しています:

#!/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 をサポートするように作成されています。

注:ベース-uのスクリプトには引数subprocessがあり、非対話モードでも利用可能になるとすぐに行を読み取ることができます。pexpectベースのスクリプトは、そのようなスイッチがなくても機能します。ベースのプログラムは、 、ユーティリティを使用するか、 pty を提供することでstdio、バッファリングを解除/行バッファリングすることができます。stdbufunbuffer

square.py最も単純な子スクリプト ( ) でさえ、機能するためにいくつかの問題を克服する必要があることがわかります。

子プログラムが別のプログラムから実行されることを期待している一方で、人間が読める (デバッグ可能) ままである場合、すべてがより簡単になります。この場合、次のsquare.pyようになります。

#!/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

subprocess「一度に」モードでベースのモジュールから使用できます。

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())

または一度に 1 つの数字:

#!/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ます:

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
于 2013-11-25T12:08:02.100 に答える
0

「連続インタラクティブ」は、OS レベルのパイプを使用するモジュールとひどく競合しsubprocessます (Unix ライクなシステムでは、Windows では必然的に少し異なることを行います)。ただし、ssh pty 接続など、ユーザーが行う方法でプロセスと対話するには、pty セッションを作成する必要があります。多くのプログラムは、パイプとやり取りするとき、またはパイプを介して対話型ではないことを前提としています。

pexpect モジュールは、古い Don Libes の Expect を Python に翻訳したものです。このような考え方を目指しています。

sh モジュールには、目的の結果を得るために必要な要素も含まれているようです。

(私自身はどちらも使用していません。)

于 2013-11-25T05:57:55.073 に答える