Как отобразить вывод консоли при запуске скрипта python из другого файла python

#python #ide #console #tkinter

#python #ide #консоль #tkinter

Вопрос:

Я создаю простую IDE с текстовым полем и кнопкой запуска. При этом пользователю предлагается ввести имя файла, записывается код, записанный в файл, и выполняется этот файл. Я хочу показывать все, что выводится с консоли, например, печать, ввод и т.д., Как это делают IDE. Возможно ли это?

Вот мой код:

 from Tkinter import *
import tkFileDialog
import ScrolledText
import subprocess
filepath=""
def run():
    global filepath
    print "<<<<<<=====-------------Restart-------------=====>>>>>>"
    py=code.get(1.0,END)
    if filepath=="":
        filepath=tkFileDialog.asksaveasfilename()
        if ".py" not in filepath:
            filepath=filepath ".py"
    script=open(filepath, "w")
    script.write(py)
    script.close()
    p = subprocess.Popen(['python', filepath],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT,
                         )
    for line in iter(p.stdout.readline, ''):
        print line
    print "<<<<<<=====-------------EXECUTION FINISHED-------------=====>>>>>>"
root = Tk()
code=ScrolledText.ScrolledText(root)
code.pack()
run=Button(root,text="Run", command=run)
run.pack()
root.mainloop()
  

Комментарии:

1. Конечно, это возможно. Если бы это было невозможно, другие IDE не смогли бы этого сделать, не могли бы они теперь? Попробуйте запустить пользовательскую программу как подпроцесс и записать ее вывод.

2. Ха, хорошая мысль, никогда не понимал, как работает IDE, пока не попробовал ее создать!

Ответ №1:

Да, просто используйте модуль subprocess.

Получение вывода за один раз

 import subprocess

output = subprocess.check_output(['python', filepath])
  

Если вы хотите зафиксировать стандартную ошибку вызываемого процесса, а также стандартный вывод, используйте это вместо:

 output = subprocess.check_output(['python', filepath], stderr=subprocess.STDOUT)
  

Или, если вы хотите записать их отдельно:

 p = subprocess.Popen(['python', filepath],
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     )
out, err = p.communicate()
  

Получение вывода по мере его создания

Это дает вам комбинированный вывод stdout и strerr, построчно:

 p = subprocess.Popen(['python', filepath],
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     )

for line in iter(p.stdout.readline, ''):
    # process the line
  

Сохранение адаптивного пользовательского интерфейса

Если вы запускаете приведенный выше код в том же потоке, что и ваш графический интерфейс, вы, по сути, блокируете выполнение цикла событий Tk во время ожидания каждой строки. Это означает, что, хотя вы получаете каждую строку в режиме реального времени и записываете ее в свой графический интерфейс, он не обновит отображение до тех пор, пока цикл событий не запустится снова и не обработает все ваши вызовы Tk.

Вам нужно запустить код подпроцесса в новом потоке, а в вашем потоке GUI периодически проверять наличие нового ввода.

Я сделал для вас пример на основе вашего, вы можете найти его здесь:

http://pastebin.com/FRFpaeJ2

Комментарии:

1. Ошибка при печати и вывод работает, но как мне распечатать его в том виде, в каком он был выведен в том же порядке? Это запускает всю программу, собирает ошибки и выходные данные и печатает их после завершения работы main… Я хочу, чтобы он печатался так, как это делает консольный ввод-вывод.

2. Смотрите мою правку для этого. Если вы хотите stdout и stderr отдельно, то это сложнее, так как вам нужно использовать потоки. Дайте мне знать, требуется ли это.

3. Таким образом, редактирование выведет все выходные данные и ошибки в порядке их отправки? Что, если я хочу, чтобы он печатался по мере отправки? В этом случае он выводит их в таком порядке, но, допустим, я должен ввести код, который печатает «Hello World» и использует time.sleep(1) и печатает его снова. Я хочу, чтобы он печатал и выводил следующую инструкцию после задержки в 1 секунду. Это редактирование просто напечатало бы два отпечатка сразу после завершения работы программы в подпроцессе. Есть ли способ сделать это?

4.Да, эта версия работает, но я ввел код print "Hello" time.sleep(5) print "Hello" , но когда я нажимаю выполнить, программа в подпроцессе ожидает завершения программы в течение 5 секунд, а затем печатает два приветственных мира, я хочу, чтобы он печатал первый по мере его вывода, а затем следующий по мере его вывода через 5 секунд.

5. Я не понимаю этот последний комментарий …?