我希望能够从我的python应用程序中启动一个交互式python终端。我程序中的一些(但不是全部)变量需要公开给解释器。
目前,我使用一个子类并进行了修改,QPlainTextEdit并将所有“命令”路由到eval或exec,并在字典中跟踪单独的命名空间。但是,必须有一种更优雅,更强大的方法!怎么样?
QPlainTextEdit
eval
exec
这是一个只做我想做的示例,但它是使用IPython和pyGTK进行的… http://ipython.scipy.org/moin/Cookbook/EmbeddingInGTK
以下是我目前拥有的。但是有很多极端的情况,我可能错过了一些。这非常慢,请尝试大的打印循环…这必须是一种更简单且不易出错的方式,…我希望!
该def runCommand(self)功能是了解我的问题的关键。理想情况下,我不想对其进行改进,而是希望以更简单,更智能的方式替换其内容。
def runCommand(self)
console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})“ main”中语句的功能也很重要。
console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
import sys, os import traceback from PyQt4 import QtCore from PyQt4 import QtGui class Console(QtGui.QPlainTextEdit): def __init__(self, prompt='$> ', startup_message='', parent=None): QtGui.QPlainTextEdit.__init__(self, parent) self.prompt = prompt self.history = [] self.namespace = {} self.construct = [] self.setGeometry(50, 75, 600, 400) self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) self.setUndoRedoEnabled(False) self.document().setDefaultFont(QtGui.QFont("monospace", 10, QtGui.QFont.Normal)) self.showMessage(startup_message) def updateNamespace(self, namespace): self.namespace.update(namespace) def showMessage(self, message): self.appendPlainText(message) self.newPrompt() def newPrompt(self): if self.construct: prompt = '.' * len(self.prompt) else: prompt = self.prompt self.appendPlainText(prompt) self.moveCursor(QtGui.QTextCursor.End) def getCommand(self): doc = self.document() curr_line = unicode(doc.findBlockByLineNumber(doc.lineCount() - 1).text()) curr_line = curr_line.rstrip() curr_line = curr_line[len(self.prompt):] return curr_line def setCommand(self, command): if self.getCommand() == command: return self.moveCursor(QtGui.QTextCursor.End) self.moveCursor(QtGui.QTextCursor.StartOfLine, QtGui.QTextCursor.KeepAnchor) for i in range(len(self.prompt)): self.moveCursor(QtGui.QTextCursor.Right, QtGui.QTextCursor.KeepAnchor) self.textCursor().removeSelectedText() self.textCursor().insertText(command) self.moveCursor(QtGui.QTextCursor.End) def getConstruct(self, command): if self.construct: prev_command = self.construct[-1] self.construct.append(command) if not prev_command and not command: ret_val = '\n'.join(self.construct) self.construct = [] return ret_val else: return '' else: if command and command[-1] == (':'): self.construct.append(command) return '' else: return command def getHistory(self): return self.history def setHisory(self, history): self.history = history def addToHistory(self, command): if command and (not self.history or self.history[-1] != command): self.history.append(command) self.history_index = len(self.history) def getPrevHistoryEntry(self): if self.history: self.history_index = max(0, self.history_index - 1) return self.history[self.history_index] return '' def getNextHistoryEntry(self): if self.history: hist_len = len(self.history) self.history_index = min(hist_len, self.history_index + 1) if self.history_index < hist_len: return self.history[self.history_index] return '' def getCursorPosition(self): return self.textCursor().columnNumber() - len(self.prompt) def setCursorPosition(self, position): self.moveCursor(QtGui.QTextCursor.StartOfLine) for i in range(len(self.prompt) + position): self.moveCursor(QtGui.QTextCursor.Right) def runCommand(self): command = self.getCommand() self.addToHistory(command) command = self.getConstruct(command) if command: tmp_stdout = sys.stdout class stdoutProxy(): def __init__(self, write_func): self.write_func = write_func self.skip = False def write(self, text): if not self.skip: stripped_text = text.rstrip('\n') self.write_func(stripped_text) QtCore.QCoreApplication.processEvents() self.skip = not self.skip sys.stdout = stdoutProxy(self.appendPlainText) try: try: result = eval(command, self.namespace, self.namespace) if result != None: self.appendPlainText(repr(result)) except SyntaxError: exec command in self.namespace except SystemExit: self.close() except: traceback_lines = traceback.format_exc().split('\n') # Remove traceback mentioning this file, and a linebreak for i in (3,2,1,-1): traceback_lines.pop(i) self.appendPlainText('\n'.join(traceback_lines)) sys.stdout = tmp_stdout self.newPrompt() def keyPressEvent(self, event): if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): self.runCommand() return if event.key() == QtCore.Qt.Key_Home: self.setCursorPosition(0) return if event.key() == QtCore.Qt.Key_PageUp: return elif event.key() in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Backspace): if self.getCursorPosition() == 0: return elif event.key() == QtCore.Qt.Key_Up: self.setCommand(self.getPrevHistoryEntry()) return elif event.key() == QtCore.Qt.Key_Down: self.setCommand(self.getNextHistoryEntry()) return elif event.key() == QtCore.Qt.Key_D and event.modifiers() == QtCore.Qt.ControlModifier: self.close() super(Console, self).keyPressEvent(event) welcome_message = ''' --------------------------------------------------------------- Welcome to a primitive Python interpreter. --------------------------------------------------------------- ''' if __name__ == '__main__': app = QtGui.QApplication(sys.argv) console = Console(startup_message=welcome_message) console.updateNamespace({'myVar1' : app, 'myVar2' : 1234}) console.show(); sys.exit(app.exec_())
我知道有点晚,但是我推荐使用 code.InteractiveConsole 类:http : _//docs.python.org/py3k/library/code.html#code.InteractiveConsole_