Вы можете создать подкласс InteractiveConsole (из встроенного модуля 'code') и переопределить метод push () с помощью оболочки, которая перенаправляет stdout / stderr на экземпляр StringIO перед отправкой в базовый метод push () InteractiveConsole.Ваша оболочка может вернуть 2-кортеж (больше, результат), где «больше» указывает, ожидает ли InteractiveConsole больше ввода, а «результат» - это то, что InteractiveConsole.push () записало в ваш экземпляр StringIO.
Звучит сложнеечем это.Вот основная предпосылка:
import sys
from cStringIO import StringIO
from code import InteractiveConsole
from contextlib import contextmanager
__all__ = ['Interpreter']
@contextmanager
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.stderr):
"""Temporarily redirect stdin/stdout/stderr"""
tmp_fds = stdin, stdout, stderr
orig_fds = sys.stdin, sys.stdout, sys.stderr
sys.stdin, sys.stdout, sys.stderr = tmp_fds
yield
sys.stdin, sys.stdout, sys.stderr = orig_fds
class Interpreter(InteractiveConsole):
"""Remote-friendly InteractiveConsole subclass
This class behaves just like InteractiveConsole, except that it
returns all output as a string rather than emitting to stdout/stderr
"""
banner = ("Python %s\n%s\n" % (sys.version, sys.platform) +
'Type "help", "copyright", "credits" or "license" '
'for more information.\n')
ps1 = getattr(sys, "ps1", ">>> ")
ps2 = getattr(sys, "ps2", "... ")
def __init__(self, locals=None):
InteractiveConsole.__init__(self, locals=locals)
self.output = StringIO()
self.output = StringIO()
def push(self, command):
"""Return the result of executing `command`
This function temporarily redirects stdout/stderr and then simply
forwards to the base class's push() method. It returns a 2-tuple
(more, result) where `more` is a boolean indicating whether the
interpreter expects more input [similar to the base class push()], and
`result` is the captured output (if any) from running `command`.
"""
self.output.reset()
self.output.truncate()
with std_redirector(stdout=self.output, stderr=self.output):
try:
more = InteractiveConsole.push(self, command)
result = self.output.getvalue()
except (SyntaxError, OverflowError):
pass
return more, result
Посмотрите на этот полный пример, который принимает ввод от сокета UDP:
Startдве консоли и запустите server.py в одной, client.py в другой.То, что вы видите в client.py, должно быть неотличимо от обычного интерактивного интерпретатора python, даже если все команды возвращаются в server.py для оценки.
Конечно, использование таких сокетов ужасно небезопасно, ноон показывает, как асинхронно оценивать внешний вход.Вы должны быть в состоянии адаптировать его к вашей ситуации, если вы доверяете источнику ввода.Вещи становятся «интересными», когда кто-то печатает:
while True: continue
Но это совсем другая проблема ...: -)