Перенаправить печать в список строк?
Я знаю, как перенаправить печать в файл.
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()
Мне нужно сделать то же самое, но без файла: сохранить вывод печати в списке строк. Как это сделать в Py3k?
Изменить: у меня могут быть сторонние отпечатки в средней части, а не мои собственные отпечатки, поэтому код должен быть универсальным для обычного "print()".
Ответы
Ответ 1
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)
дает
['i = ', ' ', '0', '\n', 'i = ', ' ', '1', '\n']
Совет. Вам не нужно сохранять оригинал sys.stdout
orig_stdout = sys.stdout
так как sys.stdout
может быть reset с
sys.stdout = sys.__stdout__
Вы также можете добавить синтаксический сахар, сделав ListStream
контекстманером:
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__
Добавив методы __enter__
и __exit__
, вы можете теперь использовать ListStream
в with-statement
, который будет автоматически reset sys.stdout
для вас, когда Python выйдет из with-suite
:
with ListStream() as x:
for i in range(2):
print ('i = ', i)
print(x.data)
Ответ 2
Вместо того, чтобы загружать свой собственный класс, я думаю, что проще всего заменить sys.stdout
(который является просто TextIOWrapper
) с экземпляром StringIO
, на который вы ссылаетесь:
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']
Как говорит @unutbu, вы можете восстановить исходный stdout с помощью sys.stdout = sys.__stdout__
; Мне особенно нравится идея использования диспетчера контекстов для временного перенаправления stdout туда, куда вы хотите.
Ответ 3
Я бы написал функцию, чтобы сделать это для вас, вместо того, чтобы пытаться перенаправить stdout
в список (который, как я думаю, не может работать в любом случае, но не цитируйте меня на этом).
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"]
Ответ 4
Это то, что я часто делаю, когда мне нужно создать приложение ncurses
:
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__
он отлично работает с python 3 и python 2.