Reputation: 1154
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.
Upvotes: 56
Views: 48714
Reputation: 262939
You 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())
Upvotes: 18
Reputation: 1612
You could combine exec with eval to get an output as list:
ExecString('i = [0,1,2]');
println(EvalStr('[j for j in i]'));
Upvotes: -1
Reputation: 107608
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())
Upvotes: 71
Reputation: 153872
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.
Upvotes: 4
Reputation: 8047
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())
Upvotes: 13
Reputation: 6754
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
Upvotes: 3
Reputation: 2965
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
Upvotes: 1