I want to get the output of an exec(...) Here is my code:
code = """ i = [0,1,2] for j in i : print j """ result = exec(code) How could I get the things that print outputed? How can I get something like:
0 1 2 Regards and thanks.
Since Python 3.4 there is a solution is the stdlib: https://docs.python.org/3/library/contextlib.html#contextlib.redirect_stdout
from io import StringIO from contextlib import redirect_stdout f = StringIO() with redirect_stdout(f): help(pow) s = f.getvalue() In older versions you can write a context manager to handle replacing stdout:
import sys from io import StringIO import contextlib @contextlib.contextmanager def stdoutIO(stdout=None): old = sys.stdout if stdout is None: stdout = StringIO() sys.stdout = stdout yield stdout sys.stdout = old code = """ i = [0,1,2] for j in i : print j """ with stdoutIO() as s: exec(code) print("out:", s.getvalue()) @contextlib.contextmanager lineYou can redirect the standard output to a string for the duration of the exec call:
import sys from cStringIO import StringIO code = """ i = [0,1,2] for j in i: print(j) """ old_stdout = sys.stdout redirected_output = sys.stdout = StringIO() exec(code) sys.stdout = old_stdout print(redirected_output.getvalue()) import sys from io import StringIO code = """ i = [0,1,2] for j in i: print(j) """ old_stdout = sys.stdout redirected_output = sys.stdout = StringIO() exec(code) sys.stdout = old_stdout print(redirected_output.getvalue()) StringIO from io => from io import StringIO.Here is Py3-friendly version of @Jochen's answer. I also added try-except clause to recover in case of errors in the code.
import sys from io import StringIO import contextlib @contextlib.contextmanager def stdoutIO(stdout=None): old = sys.stdout if stdout is None: stdout = StringIO() sys.stdout = stdout yield stdout sys.stdout = old code = """ i = [0,1,2] for j in i : print(j) """ with stdoutIO() as s: try: exec(code) except: print("Something wrong with the code") print("out:", s.getvalue()) import io, sys print(sys.version) #keep a named handle on the prior stdout old_stdout = sys.stdout #keep a named handle on io.StringIO() buffer new_stdout = io.StringIO() #Redirect python stdout into the builtin io.StringIO() buffer sys.stdout = new_stdout #variable contains python code referencing external memory mycode = """print( local_variable + 5 )""" local_variable = 2 exec(mycode) #stdout from mycode is read into a variable result = sys.stdout.getvalue().strip() #put stdout back to normal sys.stdout = old_stdout print("result of mycode is: '" + str(result) + "'") Prints:
3.4.8 result of mycode is: '7' Also a reminder that python exec(...) is evil and bad because 1. It makes your code into unreadable goto-spaghetti. 2. Introduces end-user code injection opportunities, and 3. Throws the exception stacktrace into chaos because exec is made of threads and threads are bad mmkay.
Here is a small correction of Frédéric's answer. We need to handle a possible exception in exec() to return back normal stdout. Otherwise we could not see farther print outputs:
code = """ i = [0,1,2] for j in i : print j """ from cStringIO import StringIO old_stdout = sys.stdout redirected_output = sys.stdout = StringIO() try: exec(code) except: raise finally: # ! sys.stdout = old_stdout # ! print redirected_output.getvalue() ... print 'Hello, World!' # now we see it in case of the exception above Something like:
codeproc = subprocess.Popen(code, stdout=subprocess.PIPE) print(codeproc.stdout.read()) should execute the code in a different process and pipe the output back to your main program via codeproc.stdout. But I've not personally used it so if there's something I've done wrong feel free to point it out :P