Как сделать снимок вывода на печать другого модуля?

Мне было интересно, возможно ли это в python:

# module1
def test():
    print('hey')

# module2
import module1

module1.test() # prints to stdout

Без изменения module1 есть ли способ обернуть это в module2, чтобы я мог зафиксировать print('hey') внутри переменной? Помимо запуска module1 в качестве сценария?


person waka-waka-waka    schedule 02.04.2014    source источник
comment
возможный дубликат Могу ли я перенаправить stdout в python в какой-то строковый буфер?   -  person g.d.d.c    schedule 03.04.2014


Ответы (6)


Да, ты можешь. Вам нужно взять под контроль sys.stdout. Что-то вроде этого:

import sys

stdout_ = sys.stdout #Keep track of the previous value.
sys.stdout = open('myoutputfile.txt', 'w') # Something here that provides a write method.
# calls to print, ie import module1
sys.stdout = stdout_ # restore the previous stdout.
person g.d.d.c    schedule 02.04.2014
comment
Вам не нужна первая строка - вы можете восстановить стандартный вывод по умолчанию, заменив последнюю строку на: sys.stdout = sys.__stdout__ - person otocan; 29.06.2018

Да, все, что вам нужно, это перенаправить stdout в буфер памяти, соответствующий интерфейсу stdout, вы можете сделать это с помощью StringIO. Это работает для меня в 2.7:

import sys
import cStringIO

stdout_ = sys.stdout #Keep track of the previous value.
stream = cStringIO.StringIO()
sys.stdout = stream
print "hello" # Here you can do whatever you want, import module1, call test
sys.stdout = stdout_ # restore the previous stdout.
variable = stream.getvalue()  # This will get the "hello" string inside the variable
person drodri    schedule 02.04.2014
comment
Таким образом, sys.stdout.encoding будет другим (после изменения stdout), stdout предоставляет больше, чем просто write - person dashesy; 22.09.2017

Я не хочу быть ответственным за изменение sys.stdout и последующее восстановление его до прежних значений. В приведенных выше ответах нет предложения finally:, что может быть опасно встраивать его в другой важный код.

https://docs.python.org/3/library/contextlib.html

import contextlib, io

f = io.StringIO()
with contextlib.redirect_stdout(f):
    module1.test()
output = f.getvalue()

Вероятно, вам понадобится переменная output, которая равна <class 'str'> с перенаправленным стандартным выводом.

Примечание: этот код взят из официальных документов с тривиальными модификациями (но протестирован). Другая версия этого ответа уже была дана здесь на в основном дублированный вопрос: https://stackoverflow.com/a/22434594/1092940

Я оставляю ответ здесь, потому что это намного лучшее решение, чем другие здесь, ИМО.

person AlanSE    schedule 09.09.2019

Для Python 3:

# redirect sys.stdout to a buffer
import sys, io
stdout = sys.stdout
sys.stdout = io.StringIO()

# call module that calls print()
import module1
module1.test()

# get output and restore sys.stdout
output = sys.stdout.getvalue()
sys.stdout = stdout

print(output)
person Tom    schedule 08.08.2017

Нет необходимости использовать другой модуль, просто объект класса с атрибутом записи, с одним входом, который вы можете сохранить в другой переменной. например

КЛАСС:

class ExClass:
    def __init__(self):
        self.st = ''
    def write(self, o): #here o is the output that goes to stdout
        self.st += str(o)

ОСНОВНАЯ Программа:

import sys
stdout_ = sys.stdout
var = ExClass()
sys.stdout = var

print("Hello") # these will not be pronted 
print("Hello2") # instead will be written in var.st

sys.stdout = stdout_

print(var.st) 

выход будет

Hello
Hello2
person jimmy kumar ahalpara    schedule 16.11.2019

Отправка отладочной информации ftplib в модуль регистрации

Основываясь на подходе, принятом jimmy kumar ahalpara ответом, я смог записать отладочные данные ftplib в logging. ftplib существовал до модуля регистрации и использует print для отправки отладочных сообщений.

Я пытался переназначить функцию печати методу ведения журнала, но у меня не получалось заставить это работать. Код ниже работает для меня.

Я думаю, это будет работать и с другими модулями, но не будет никакой детализации между выходными данными разных модулей, поскольку он фиксирует все, что отправлено на stdout в один и тот же регистратор.

# convenience class to redirect stdout to logging
class SendToLog:

    def __init__(self, logging_method):

        self.logger = logging
_method
    def write(self, o):

        if str(o).strip():  #  ignore empty lines
            self.logger(str(o))


import logging
import sys

# code to initialise logging output and handlers ...
# ...

# get logger for ftplib and redirect it's print output to our log
ftp_logger = logging.getLogger('ftplib')
# note: logging's debug method is passed to the class, the instance then calls this method
sys.stdout = SendToLog(ftp_logger.debug)

# code to do stuff with ftplib ...
# remember to set ftplib's debug level > 0 or there will be no output
# FTP.set_debuglevel(1)
# ...

# important to finalise logging and restore stdout
logging.shutdown()
sys.stdout = sys.__stdout__

python3 stdout ftplib ведение журнала

person adejones    schedule 24.01.2020