人間と対話するように設計されたプログラムは、他のプログラムと対話するように設計されたプログラムとは異なります。あなたの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
、バッファリングを解除/行バッファリングすることができます。stdbuf
unbuffer
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