Вы можете перенаправить stdout / stderr в StringIO в myfunc (), а затем отправить все, что записано в этот StringIO, обратно родителю (как предложено unutbu). См. Мой ответ на этот вопрос , чтобы узнать об одном способе перенаправления.
Поскольку этот пример делает немного больше, чем вам нужно, вот версия, которая больше соответствует вашим заявленным целям:
#!/usr/bin/env python
import sys
from cStringIO import StringIO
from code import InteractiveConsole
from contextlib import contextmanager
from multiprocessing import Process, Pipe
@contextmanager
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.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):
def __init__(self, locals=None):
InteractiveConsole.__init__(self, locals=locals)
self.output = StringIO()
self.output = StringIO()
def push(self, 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
def myfunc(conn, commands):
output = StringIO()
py = Interpreter()
results = ""
for line in commands.split('\n'):
if line and len(line) > 0:
more, result = py.push(line + '\n')
if result and len(result) > 0:
results += result
conn.send(results)
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
commands = """
print "[42, None, 'hello']"
def greet(name, count):
for i in range(count):
print "Hello, " + name + "!"
greet("Beth Cooper", 5)
fugazi
print "Still going..."
"""
p = Process(target=myfunc, args=(child_conn, commands))
p.start()
print parent_conn.recv()
p.join()
Здесь действуют обычные предостережения о безопасности (то есть, не делайте этого, если вы не можете доверять отправителю этих фрагментов кода, чтобы он не делал ничего глупого / злонамеренного).
Также обратите внимание, что вы можете значительно упростить это, если вам не нужно интерпретировать произвольное сочетание выражений Python и . Если вам нужно только вызвать функцию верхнего уровня, которая генерирует некоторые выходные данные, может подойти что-то вроде этого:
def dosomething():
print "Doing something..."
def myfunc(conn, command):
output = StringIO()
result = ""
with std_redirector(stdout=output, stderr=output):
try:
eval(command)
result = output.getvalue()
except Exception, err:
result = repr(err)
conn.send(result)
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
command = "dosomething()"
p = Process(target=myfunc, args=(child_conn, command))
p.start()
print parent_conn.recv()
p.join()