Python - подпроцессы и оболочка python - PullRequest
5 голосов
/ 01 декабря 2011

Я пытаюсь создать оболочку для подпроцесса, отличного от python, и позволить ему наследовать stdin и stdout от python. - Я использую подпроцесс. Открыть

Это, вероятно, будет работать, если я звоню с консоли, но определенно не работает, когда я использую оболочку python

(кстати, я использую IDLE)

Есть ли способ убедить python разрешить подпроцессу, отличному от python, выводить свой стандартный вывод в оболочку python?

Ответы [ 2 ]

6 голосов
/ 01 декабря 2011

Это работает как из скрипта, так и из интерактивного интерпретатора, но не из IDLE:

subprocess.Popen(whatever, stdin=sys.stdout, stdout=sys.stdin)

Нельзя использовать объекты, которые IDLE присваивает sys.stdin и sys.stdout в качестве аргументов subprocess.Popen. Эти объекты (интерфейсы к окну оболочки IDLE) похожи на файлы, но они не являются настоящими файловыми дескрипторами с атрибутами fileno, и Unix-подобные операционные системы требуют, чтобы fileno был указан как stdin или stdout для подпроцесса , Я не могу говорить за Windows, но я предполагаю, что к ней предъявляются аналогичные требования.

4 голосов
/ 01 декабря 2011

Ответ Теймона обращается к вашему вопросу непосредственно в том, что stdin / stdout IDLE на самом деле являются файловыми объектами, а не стандартными файловыми потоками, связанными с консолью / терминалом. Более того, в Windows IDLE работает с pythonw.exe, к которому даже не подключена консоль win32.

Тем не менее, если вам просто нужно, чтобы вывод программы был распечатан пользователю в реальном времени, то во многих случаях (но не во всех) вы можете читать строку вывода построчно и отображать его соответствующим образом. Следующее работает для меня в Windows IDLE. Это демонстрирует чтение из переданного по каналу stdout построчно. Он также показывает, что произойдет, если процесс буферизует канал, и в этом случае readline будет блокироваться до тех пор, пока буфер не заполнится или канал не закроется. Эту буферизацию можно отключить вручную в некоторых программах (например, в параметре -u интерпретатора Python), и для Unix есть обходные пути, такие как stdbuf .

test1.py

import sys
import subprocess

def test(cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, 
                         stderr=subprocess.PIPE)
    it = iter(p.stdout.readline, b'')
    for line in it:
        print(line.rstrip().decode('ascii'))

print('Testing buffered subprocess...')
test([sys.executable, 'test2.py'])

print('\nTesting unbuffered subprocess...')
#-u: unbuffered binary stdout and stderr
test([sys.executable, '-u', 'test2.py']) 

test2.py:

import time

for i in range(5):
    print(i)
    time.sleep(1)

Вывод в режиме IDLE должен быть следующим: первый набор цифр печатается сразу после задержки, а второй набор печатается построчно.

Testing buffered subprocess...
0
1
2
3
4

Testing unbuffered subprocess...
0
1
2
3
4
...