Заставьте stdout замолчать функции в Python, не повреждая sys.stdout и восстановив каждый вызов функции

Существует ли путь в Python к тишине stdout, не перенося вызов функции как следующее?

Исходный взломанный код:

from sys import stdout
from copy import copy
save_stdout = copy(stdout)
stdout = open('trash','w')
foo()
stdout = save_stdout

Править: Исправленный код от Alex Martelli

import sys
save_stdout = sys.stdout
sys.stdout = open('trash', 'w')
foo()
sys.stdout = save_stdout

Тот путь работает, но, кажется, ужасно неэффективен. Должен быть лучший путь. Какие-либо идеи?

45
задан Michael Currie 7 May 2015 в 22:59
поделиться

3 ответа

Назначение stdout переменная, которую вы делаете, не имеет никакого эффекта, если предположить, что foo содержит print операторов - еще один пример того, почему вы никогда не должны импортировать данные из внутри модуль (как вы это делаете здесь), но всегда модуль в целом (тогда используйте уточненные имена). Кстати, копия не имеет значения. Правильный эквивалент вашего фрагмента:

import sys
save_stdout = sys.stdout
sys.stdout = open('trash', 'w')
foo()
sys.stdout = save_stdout

Теперь , когда код правильный, самое время сделать его более элегантным или быстрым. Например, вы можете использовать файл-подобный объект в памяти вместо файла 'trash':

import sys
import io
save_stdout = sys.stdout
sys.stdout = io.BytesIO()
foo()
sys.stdout = save_stdout

для элегантности, context лучше всего, например:

import contextlib
import io
import sys

@contextlib.contextmanager
def nostdout():
    save_stdout = sys.stdout
    sys.stdout = io.BytesIO()
    yield
    sys.stdout = save_stdout

после того, как вы определили этот контекст, для любого блока, в котором вам не нужен стандартный вывод,

with nostdout():
    foo()

Дополнительная оптимизация: вам просто нужно заменить sys.stdout на объект, у которого есть метод no-op write . Например:

import contextlib
import sys

class DummyFile(object):
    def write(self, x): pass

@contextlib.contextmanager
def nostdout():
    save_stdout = sys.stdout
    sys.stdout = DummyFile()
    yield
    sys.stdout = save_stdout

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

82
ответ дан 26 November 2019 в 20:52
поделиться

Как вы думаете, почему это неэффективно? Вы тестировали это? Кстати, он вообще не работает, потому что вы используете оператор from ... import . Заменить sys.stdout можно, но не сделайте копию и не используйте временный файл. Вместо этого откройте пустое устройство:

import sys
import os

def foo():
    print "abc"

old_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
try:
    foo()
finally:
    sys.stdout.close()
    sys.stdout = old_stdout
15
ответ дан 26 November 2019 в 20:52
поделиться

Небольшая модификация ответа Алекса Мартелли ...

Это касается случая, когда вы всегда хотите подавить stdout для функции вместо отдельных вызовов функции.

Если бы foo () вызывался много раз, было бы лучше / проще обернуть функцию (украсить ее). Таким образом, вы изменяете определение foo один раз вместо того, чтобы заключать каждое использование функции в оператор with.

import sys
from somemodule import foo

class DummyFile(object):
    def write(self, x): pass

def nostdout(func):
    def wrapper(*args, **kwargs):        
        save_stdout = sys.stdout
        sys.stdout = DummyFile()
        func(*args, **kwargs)
        sys.stdout = save_stdout
    return wrapper

foo = nostdout(foo)
5
ответ дан 26 November 2019 в 20:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: