Как использовать оператор with для подавления sys.stdout или sys.stderr?

Я пытаюсь использовать оператор with для подавления sys.stdout или sys.stderr по отдельности. Я нашел tutorial, который не работал. Я использую Python 3.6.4 и думаю, что туториал — это какая-то версия Python 2.

Я просмотрел его на SO и нашел несколько, но с приложениями, которые не работали или не применялись к этой ситуации.

Это неприменимо: подпроцесс Python подавляет стандартный вывод и стандартный вывод

Не удалось заставить работать ни один из операторов with: Подавить печать stdout/stderr из Функции Python

Это для фортрана: Перенаправление FORTRAN (вызывается через F2PY) вывод на Python

from contextlib import contextmanager
@contextmanager
def suppress_console(file=sys.stdout):
    with open(os.devnull, "w") as devnull:
        old_file = file
        file = devnull
        try:  
            yield
        finally:
            file = old_file

with suppress_console():
    print(1, file=sys.stdout)
# 1

person O.rka    schedule 05.06.2018    source источник
comment
Вы понимаете, что contextlib уже включает в себя redirect_stdout и redirect_stderr диспетчеры контекста, верно? Просто перенаправьте на os.devnull   -  person juanpa.arrivillaga    schedule 05.06.2018
comment
Но причина, по которой это не работает, заключается в том, что вы просто переназначаете локальную переменную old_file. Вам нужно изменить атрибуты sys.   -  person juanpa.arrivillaga    schedule 05.06.2018


Ответы (2)


Я использую что-то вроде этого:

class Suppress:
    def __init__(self, *, suppress_stdout=False, suppress_stderr=False):
        self.suppress_stdout = suppress_stdout
        self.suppress_stderr = suppress_stderr
        self.original_stdout = None
        self.original_stderr = None

    def __enter__(self):
        import sys, os
        devnull = open(os.devnull, "w")

        # Suppress streams
        if self.suppress_stdout:
            self.original_stdout = sys.stdout
            sys.stdout = devnull

        if self.suppress_stderr:
            self.original_stderr = sys.stderr
            sys.stderr = devnull

    def __exit__(self, *args, **kwargs):
        import sys
        # Restore streams
        if self.suppress_stdout:
            sys.stdout = self.original_stdout

        if self.suppress_stderr:
            sys.stderr = self.original_stderr

Пример:

import sys
print("Before")
with Suppress(suppress_stdout=True):
    print("Inside")
print("After")

print("Before", file=sys.stderr)
with Suppress(suppress_stderr=True):
    print("Inside", file=sys.stderr)
print("After", file=sys.stderr)

Вывод:

Before
After
Before
After

Примечания:

  • Я поместил свои импорты внутри методов для чистоты, но обычно это было бы внутри файла модуля с импортами вверху.
  • Подавление stderr рискованно, особенно из-за того, как я (не) обрабатываю исключения в методе __exit__. Вы можете рассмотреть возможность создания более надежного метода выхода.
person jedwards    schedule 05.06.2018
comment
Вау, этот код имеет отличный стиль. Большое спасибо за это. Я не совсем уверен, как работают операторы и объекты, совместимые с операторами, но это определенно дает мне некоторое представление. - person O.rka; 05.06.2018

Я использую следующий:

from contextlib import redirect_stdout, contextmanager
import os


@contextmanager
def suppress():
    with open(os.devnull, "w") as null:
        with redirect_stdout(null):
            yield

тестовое задание:

print("qwer")
with suppress():
    print("asdf")
print("ghjk")
# qwer
# ghjk

Обновить

Лучше:

from contextlib import redirect_stdout, redirect_stderr, contextmanager, ExitStack
import os

@contextmanager
def suppress(out=True, err=False):
    with ExitStack() as stack:
        with open(os.devnull, "w") as null:
            if out:
                stack.enter_context(redirect_stdout(null))
            if err:
                stack.enter_context(redirect_stderr(null))
            yield
person Sraw    schedule 05.06.2018