強調するために、問題は非ブロック読み取りではなくリアルタイム読み取りです。subprocess.Popen.stdout - reading stdout in real-time (again)など、以前に尋ねられました。しかし、満足のいく解決策は提案されていません。
例として、次のコードは Python シェルをシミュレートしようとします。
import subprocess
p = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
line = input('>>> ')
p.stdin.write(line.encode())
print('>>> ', p.stdout.read().decode())
ただし、から読み取るとブロックされp.stdout
ます。いろいろと調べてみると、以下の2つの解決策が見つかりました。
1 番目の解決策は機能し、Linux でのみ機能する可能性がありますが、2 番目の解決策はブロック読み取りを非ブロック読み取りに変えるだけです。つまり、サブプロセスのリアルタイム出力を取得できません。たとえば、「 」と入力すると、 2 番目のソリューションを使用してprint("hello")
も何も得られません。p.stdout
おそらく、誰かが提案するでしょうp.communite
。残念ながら、ここで説明されているように標準入力を閉じるため、この場合には適していません。
それで、Windowsの解決策はありますか?
編集済み:-u
をオンにしてp.stdout.read
に置き換えてもp.stdout.readline
、問題は依然として存在します。
import subprocess
p = subprocess.Popen(['python', '-u'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
line = input('>>> ')
p.stdin.write(line.encode())
p.stdin.flush()
print('>>> ', p.stdout.readline().decode())
解決策:以下は、JF Sebastian の回答とコメントに基づく最終的なコードです。
from subprocess import Popen, PIPE, STDOUT
with Popen(
['python', '-i', '-q'],
stdin=PIPE, stdout=PIPE, stderr=STDOUT,
bufsize=0
) as process:
while True:
line = input('>>> ')
if not line:
break
process.stdin.write((line+'\n').encode())
print(process.stdout.readline().decode(), end='')
コマンドが出力をトリガーしない場合、プログラムがハングすることに注意してください。