Python 通过GUI重定向stdin

Python 通过GUI重定向stdin,python,pyqt,pyqt4,stdin,io-redirection,Python,Pyqt,Pyqt4,Stdin,Io Redirection,我有一个非常基本的应用程序,它打算在一个textEdit组件上评估给定的Python代码,并在另一个组件上显示结果 import sys

我有一个非常基本的应用程序,它打算在一个
textEdit
组件上评估给定的Python代码,并在另一个组件上显示结果

import sys                                                                                                                                                                                      
from PyQt4 import QtGui
from cStringIO import StringIO

class SampleGUI(QtGui.QWidget):
    def __init__(self):
        super(SampleGUI, self).__init__()
        self.initGUI()

    def initGUI(self):
        self.code = QtGui.QTextEdit()
        self.result = QtGui.QTextEdit()

        btn = QtGui.QPushButton('Evaluate')
        btn.clicked.connect(self.evaluate)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.code)
        vbox.addWidget(btn)
        vbox.addWidget(self.result)

        self.setLayout(vbox)
        self.show()

    def evaluate(self):
        source_code = str(self.code.toPlainText())
        old_stdout = sys.stdout
        redirected_output = sys.stdout = StringIO()
        exec source_code
        sys.stdout = old_stdout
        self.result.setText(redirected_output.getvalue())

def main():
    app = QtGui.QApplication([])
    s = SampleGUI()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
到目前为止,它工作得很好,您不需要输入值。假设您使用
python samplegui.py
从控制台运行脚本,如果您碰巧在第一个文本框中键入类似的内容:

a = 3
print 5 + a
b = input()
print 1 + b
然后按下
Evaluate
,应用程序希望从控制台输入值。输入一些值并按enter键后,它将继续并正确计算

我想要实现的是将
stdin
重定向到一个我可以在
GUI
本身中操作的组件

我该怎么做?理想情况下,我希望使用Python解释器样式,在这种样式中,输出和输入以交互方式进行。另一个选项是在应用程序等待输入时以某种方式处理/捕获信号,并显示输入对话框

编辑:

事实证明,这比我想象的要容易。在这里,您可以看到使用
QInputDialog
截取的带有
sys.stdin
的脚本版本,因此用户可以从
GUI
输入值

import sys 
from PyQt4 import QtGui
from cStringIO import StringIO

class InputGUI():
    def __init__(self, parentWidget):
        self.parentWidget = parentWidget

    def readline(self):
        text, ok = QtGui.QInputDialog.getText(self.parentWidget, 'Introduce value', 'Value:')
        if ok: 
            return str(text)
        else:
            return ''

class SampleGUI(QtGui.QWidget):
    def __init__(self):
        super(SampleGUI, self).__init__()
        self.initGUI()

    def initGUI(self):
        self.code = QtGui.QTextEdit()
        self.result = QtGui.QTextEdit()

        btn = QtGui.QPushButton('Evaluate')
        btn.clicked.connect(self.evaluate)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.code)
        vbox.addWidget(btn)
        vbox.addWidget(self.result)

        self.setLayout(vbox)
        self.show()

    def evaluate(self):
        source_code = str(self.code.toPlainText())
        streams = sys.stdin, sys.stdout
        sys.stdin = InputGUI(self)                                                                                                                                                              
        redirected_output = sys.stdout = StringIO()
        exec source_code
        sys.stdin, sys.stdout = streams
        self.result.setText(redirected_output.getvalue())

def main():
    app = QtGui.QApplication([])
    s = SampleGUI()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()    

我将用实现文件描述符协议的自定义类的实例替换
sys.stdin
。然后,您可以简单地决定当用户希望通过
input()
sys.stdin.readline()
读取某个内容时应该发生什么

至于实现一个文件描述符:实现本文中涉及的所有方法。此外,您可能希望实现,因此您的自定义
sys.stdin
可以与
with
语句一起使用


但是,请注意,如果用户再次更换
sys.stdin
自己,仍然可能会射中自己的脚,但至少这似乎比调用
input()

的人更不可能,谢谢你为我指明了正确的方向@Christian Aichinger。我创建了一个实现
readline()
的类,这是我现在唯一需要的方法。不用担心重新替换sys.stdin,我控制要计算的代码(即由解析器生成)。我将编辑问题以添加已修改的脚本,这样它将接受来自
QInputDialog
的输入。