【问题标题】:Redirecting stdout to "nothing" in python在python中将stdout重定向到“无”
【发布时间】:2011-10-07 19:59:45
【问题描述】:

我有一个由足够多的模块组成的大型项目,每个模块都会向标准输出打印一些内容。现在随着项目规模的扩大,没有大的。的print 语句在标准输出上打印了很多,这使得程序相当慢。

所以,我现在想在 runtime 决定是否将任何内容打印到标准输出。我无法对模块进行更改,因为它们有很多。 (我知道我可以将标准输出重定向到一个文件,但即使这样也相当慢。)

所以我的问题是如何将标准输出重定向到无,即如何使print 语句什么都不做?

# I want to do something like this.
sys.stdout = None         # this obviously will give an error as Nonetype object does not have any write method.

目前我唯一的想法是创建一个具有 write 方法(什么都不做)的类,并将标准输出重定向到此类的实例。

class DontPrint(object):
    def write(*args): pass

dp = DontPrint()
sys.stdout = dp

python 中是否有为此的内置机制?或者还有什么比这更好的吗?

【问题讨论】:

  • 我刚刚发现了一件奇怪的事情。将 sys.stdout 变为 None 实际上在我的程序中有效,尽管我不确定为什么。我在编码重定向到 os.devnull 时遇到了真的奇怪的问题,所以我尝试只使用 None,它可以工作。可能与我在 Django 单元测试中做这件事有关,但我不确定。
  • @Teekin 它确实有效,并且在与 Django 无关的上下文中。

标签: python python-2.7


【解决方案1】:

跨平台:

import os
import sys
f = open(os.devnull, 'w')
sys.stdout = f

在 Windows 上:

f = open('nul', 'w')
sys.stdout = f

在 Linux 上:

f = open('/dev/null', 'w')
sys.stdout = f

【讨论】:

  • 你如何取消它?完成后有没有办法重新打开打印语句?
  • 当然,只需保存对原始sys.stdout 的引用并在之后将其设置回来。例如old_stdout = sys.stdout 在任何其他代码之前,然后sys.stdout = old_stdout 完成后。
  • 注意:它不会在文件描述符级别重定向,即,它可能无法重定向外部子进程的输出,即直接打印到 C 标准输出的 C 扩展的输出,os.write(1, b'abc\n')。您需要os.dup2(),在文件描述符级别重定向,请参阅stdout_redirected()
  • 请注意,sys.__stdout__ 用于取消重定向。因此,您只需执行sys.stdout = sys.__stdout__ 即可,无需存储备份。
  • 注意:比sys.stout = f更干净的是with contextlib.redirect_stdout(f):docs
【解决方案2】:

一个很好的方法是创建一个小型上下文处理器,您可以在其中包装您的打印。然后您只需在 with-statement 中使用 is 来使所有输出静音。

Python 2:

import os
import sys
from contextlib import contextmanager

@contextmanager
def silence_stdout():
    old_target = sys.stdout
    try:
        with open(os.devnull, "w") as new_target:
            sys.stdout = new_target
            yield new_target
    finally:
        sys.stdout = old_target

with silence_stdout():
    print("will not print")

print("this will print")

Python 3.4+:

Python 3.4 内置了这样的上下文处理器,因此您可以像这样简单地使用 contextlib:

import contextlib

with contextlib.redirect_stdout(None):
    print("will not print")

print("this will print")

如果您想要隐藏的代码使用 None 作为重定向目标直接写入 sys.stdout 将不起作用。相反,您可以使用:

import contextlib
import sys
import os

with contextlib.redirect_stdout(open(os.devnull, 'w')):
    sys.stdout.write("will not print")

sys.stdout.write("this will print")

如果您的代码写入 stderr 而不是 stdout,您可以使用 contextlib.redirect_stderr 而不是 redirect_stdout。


运行此代码只打印第二行输出,而不是第一行:

$ python test.py
this will print

这适用于跨平台(Windows + Linux + Mac OSX),并且比其他答案更干净。

【讨论】:

  • @celticminstrel 你是完全正确的,谢谢你纠正我。之后我更新了代码以重置 sys.stdout。
  • 这缺少一些错误检查,但好主意
  • 当我将 redirect_stdout(None)argparse 的输出一起使用时,它对我不起作用。但是redirect_stdout(NonWritable())(请参阅本主题)有效!
  • @user10815638:我不确定 argparse 有什么特别之处。可能是因为它是一个错误而写入 stderr 吗?在这种情况下,有 redirect_stderr。
  • @Emil Stenström:是的,argparse 输出到sdderr(并非总是如此),但contextlib.redirect_stderr(None) 显示:“NoneType”对象没有“写入”属性。我在这个主题中发布了一个更大的例子。
【解决方案3】:

如果您使用的是 python 3.4 或更高版本,使用标准库有一个简单且安全的解决方案:

import contextlib

with contextlib.redirect_stdout(None):
  print("This won't print!")

【讨论】:

  • with contextlib.redirect_stdout(None) 也可以
  • @ChrisCogdon 很好的提示,我相应地编辑了答案。
  • 如果您使用的是 pprint 库,则不起作用。 AttributeError: 'NoneType' object has no attribute 'write'
  • @Speeeddy 你在 python 2 中遇到了这个错误吗?您可以使用不执行任何操作的虚拟 write 方法创建一个类。请参阅下面的答案。
【解决方案4】:

(至少在我的系统上)似乎写入 os.devnull 比写入 DontPrint 类快约 5 倍,即

#!/usr/bin/python
import os
import sys
import datetime

ITER = 10000000
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"):
   temp = sys.stdout
   sys.stdout = out
   i = 0
   start_t = datetime.datetime.now()
   while i < it:
      print st
      i = i+1
   end_t = datetime.datetime.now()
   sys.stdout = temp
   print out, "\n   took", end_t - start_t, "for", it, "iterations"

class devnull():
   def write(*args):
      pass


printlots(open(os.devnull, 'wb'), ITER)
printlots(devnull(), ITER)

给出以下输出:

<open file '/dev/null', mode 'wb' at 0x7f2b747044b0> 
   took 0:00:02.074853 for 10000000 iterations
<__main__.devnull instance at 0x7f2b746bae18> 
   took 0:00:09.933056 for 10000000 iterations

【讨论】:

  • 记录一下,下次想计时,用timeit
【解决方案5】:

如果您在 Unix 环境中(包括 Linux),您可以将输出重定向到 /dev/null:

python myprogram.py > /dev/null

对于 Windows:

python myprogram.py > nul

【讨论】:

  • 最好有一个适用于所有平台的解决方案。
  • @Guanidene,也许,但如果他是唯一使用他的程序的人,他几乎可以保证环境。
  • nul = myfunc() ?
【解决方案6】:

您的类可以正常工作(write() 方法名称除外——它需要被称为write(),小写)。只需确保将sys.stdout 的副本保存在另一个变量中即可。

如果您使用的是 *NIX,则可以使用 sys.stdout = open('/dev/null'),但这比滚动您自己的课程更不便携。

【讨论】:

    【解决方案7】:

    这个怎么样:

    from contextlib import ExitStack, redirect_stdout
    import os
    
    with ExitStack() as stack:
        if should_hide_output():
            null_stream = open(os.devnull, "w")
            stack.enter_context(null_stream)
            stack.enter_context(redirect_stdout(null_stream))
        noisy_function()
    

    这使用contextlib 模块中的功能来隐藏您尝试运行的任何命令的输出,具体取决于should_hide_output() 的结果,然后在该函数运行完成后恢复输出行为。

    如果要隐藏标准错误输出,则从contextlib 导入redirect_stderr 并添加一行stack.enter_context(redirect_stderr(null_stream))

    主要缺点是这只适用于 Python 3.4 及更高版本。

    【解决方案8】:
    sys.stdout = None
    

    print() 情况下可以。但是如果你调用 sys.stdout 的任何方法,它可能会导致错误,例如sys.stdout.write().

    有一个note in docs

    在某些条件下stdin、stdout和stderr以及原来的 stdinstdoutstderr 的值可以为 None。通常是 未连接到控制台的 Windows GUI 应用程序和 Python 应用以 pythonw 开头。

    【讨论】:

    • “OK”和“在您尝试打印时不会抛出错误”在这种情况下是截然不同的。
    • 你是对的。您不能使用sys.stdout = Null 调用任何方法,因此在某些情况下它可能很危险。
    • 在这种确切的情况下,它被认为是危险的。 OP 专门解决了他这样做的错误。
    【解决方案9】:

    你可以模拟它。

    import mock
    
    sys.stdout = mock.MagicMock()
    

    【讨论】:

      【解决方案10】:

      iFreilicht's answer 的补充 - 它适用于 python 2 和 3。

      import sys
      
      class NonWritable:
          def write(self, *args, **kwargs):
              pass
      
      class StdoutIgnore:
          def __enter__(self):
              self.stdout_saved = sys.stdout
              sys.stdout = NonWritable()
              return self
      
          def __exit__(self, *args):
              sys.stdout = self.stdout_saved
      
      with StdoutIgnore():
          print("This won't print!")
      

      【讨论】:

        【解决方案11】:

        你为什么不试试这个?

        sys.stdout.close()
        sys.stderr.close()
        

        【讨论】:

        • 因为 A) 它甚至可能不起作用,并且 B) 如果它起作用,你会得到一个错误,而不是仅仅抑制输出。
        【解决方案12】:

        将在此处为众多答案添加一些示例:

        import argparse
        import contextlib
        
        class NonWritable:
            def write(self, *args, **kwargs):
                pass
        
        parser = argparse.ArgumentParser(description='my program')
        parser.add_argument("-p", "--param", help="my parameter", type=str, required=True)
        
        #with contextlib.redirect_stdout(None): # No effect as `argparse` will output to `stderr`
        #with contextlib.redirect_stderr(None): # AttributeError: 'NoneType' object has no attribute 'write'
        with contextlib.redirect_stderr(NonWritable): # this works!
            args = parser.parse_args()
        

        正常的输出是:

        >python TEST.py
        usage: TEST.py [-h] -p PARAM
        TEST.py: error: the following arguments are required: -p/--param
        

        【讨论】:

          【解决方案13】:

          如果您不想处理资源分配或滚动您自己的类,您可能希望使用 Python 输入中的TextIO。默认情况下,它为您提供了所有必需的方法。

          import sys
          from typing import TextIO
          
          sys.stdout = TextIO()
          

          【讨论】:

            猜你喜欢
            • 2014-07-22
            • 2014-09-13
            • 1970-01-01
            • 2019-10-11
            • 2020-06-02
            • 1970-01-01
            • 2012-08-07
            • 2017-03-08
            • 1970-01-01
            相关资源
            最近更新 更多