Reputation: 4781
I know how to redirect print to a file.
import sys
orig_stdout = sys.stdout
f = file('out.txt', 'w')
sys.stdout = f
for i in range(2):
print ('i = ', i)
sys.stdout = orig_stdout
f.close()
I need to do the same but w/out a file: keep print output in a string list. How to do it in Py3k?
Edit: I can have 3rd party prints in a middle part, not my own prints, so code must be universal for usual "print()".
Upvotes: 17
Views: 13582
Reputation: 25974
Instead of rolling your own class, I think it's easiest to replace sys.stdout
(which is simply a TextIOWrapper
) with a StringIO
instance you keep a reference to:
import sys
from io import StringIO
s = StringIO()
sys.stdout = s
print('yo')
print('this is stuff')
print('hi')
s.getvalue()
Out[38]: 'yo\nthis is stuff\nhi\n'
s.getvalue().splitlines()
Out[39]: ['yo', 'this is stuff', 'hi']
As @unutbu says, you can restore the original stdout with sys.stdout = sys.__stdout__
; I particlarly like the idea of using a context manager to temporarily redirect stdout to where you want it to go.
Upvotes: 10
Reputation: 880199
import sys
class ListStream:
def __init__(self):
self.data = []
def write(self, s):
self.data.append(s)
sys.stdout = x = ListStream()
for i in range(2):
print ('i = ', i)
sys.stdout = sys.__stdout__
print(x.data)
yields
['i = ', ' ', '0', '\n', 'i = ', ' ', '1', '\n']
Tip: You don't need to save the original sys.stdout
orig_stdout = sys.stdout
since sys.stdout
can be reset with
sys.stdout = sys.__stdout__
You could also add some syntactic sugar by making ListStream
a contextmanager:
import sys
class ListStream:
def __init__(self):
self.data = []
def write(self, s):
self.data.append(s)
def __enter__(self):
sys.stdout = self
return self
def __exit__(self, ext_type, exc_value, traceback):
sys.stdout = sys.__stdout__
By adding the __enter__
and __exit__
methods, you can now use ListStream
in a with-statement
which will automatically reset sys.stdout
for you when Python exits the with-suite
:
with ListStream() as x:
for i in range(2):
print ('i = ', i)
print(x.data)
Upvotes: 19
Reputation: 24812
That's something I often do when I need to build a ncurses
application:
import sys
# in this wrapper class you can use a string list instead of a full string like I'm doing
class StdOutWrapper:
lines = []
def write(self,txt):
self.lines.append(txt)
# here is a method so you can get stuff out of your wrapper class
# I am rebuilding the text, but you can do whatever you want!
def get_text(self,beg,end):
return '\n'.join(self.lines)
mystdout = StdOutWrapper()
sys.stdout = mystdout
sys.stderr = mystdout
# do your stuff here that needs to be printed out in a string list
for i in range(2):
print ('i = ', i)
# you don't need to make your variable to cache the `stdout`/`stderr` as they still exist
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
it is working fine with python 3 and python 2.
Upvotes: 2
Reputation: 54213
I would write a function to do it for you, rather than trying to redirect stdout
to a list (which I don't think could possibly work anyway, but don't quote me on that).
def lprint(text):
global string_list
try: string_list.append(text)
except NameError as e:
string_list = [text]
for i in range(2):
lprint ("i = {}".format(i))
print(string_list)
[OUT]: ["i = 0","i = 1"]
Upvotes: 0