Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect print to string list?

Tags:

python

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()".

like image 550
Prog1020 Avatar asked Jan 24 '14 19:01

Prog1020


People also ask

How do you define stdout in python?

A built-in file object that is analogous to the interpreter's standard output stream in Python. stdout is used to display output directly to the screen console. Output can be of any form, it can be output from a print statement, an expression statement, and even a prompt direct for input.


3 Answers

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)
like image 108
unutbu Avatar answered Sep 18 '22 22:09

unutbu


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.

like image 10
roippi Avatar answered Sep 22 '22 22:09

roippi


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.

like image 2
zmo Avatar answered Sep 21 '22 22:09

zmo