【问题标题】:How to use a `with` statement to suppress `sys.stdout` or `sys.stderr`?如何使用 `with` 语句来抑制 `sys.stdout` 或 `sys.stderr`?
【发布时间】:2018-06-05 03:23:43
【问题描述】:

我正在尝试使用 with 语句来单独抑制 sys.stdoutsys.stderr 我发现 tutorial 不起作用。我正在使用Python 3.6.4,我认为本教程是Python 2 的某个版本。

I looked it up on SO 并找到了一些但应用程序不起作用或不适用于这种情况。

这不适用:Python subprocess supress stdout and stderr

无法使任何with 语句起作用: Suppress stdout / stderr print from Python functions

这是fortran:Redirecting FORTRAN (called via F2PY) output in 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

【问题讨论】:

  • 您意识到contextlib 已经包含redirect_stdoutredirect_stderr 上下文管理器,对吧?只需重定向到os.devnull
  • 但这不起作用的原因是您只是重新分配了局部变量old_file。您需要更改sys的属性。

标签: python stdout stderr suppress dev-null


【解决方案1】:

我用的是下面这个:

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

【讨论】:

【解决方案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)

输出

前 后 前 后

注意事项:

  • 为了保持整洁,我将导入放在方法中,但通常这会放在顶部带有导入的模块文件中。
  • 抑制 stderr 是有风险的,尤其是因为我(不)在 __exit__ 方法中处理异常的方式。您可能会考虑制定更强大的退出方法。

【讨论】:

  • 哇,这个编码风格很棒。非常感谢。我不太确定 with 语句和与语句兼容的对象是如何工作的,但这无疑给了我一些见解。
猜你喜欢
  • 2014-04-11
  • 2016-05-29
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 2011-05-30
  • 1970-01-01
相关资源
最近更新 更多