在python中将stdout重定向为“ nothing”


128

我有一个大型项目,其中包含足够多的模块,每个模块都将一些内容打印到标准输出中。现在,随着项目规模的扩大,没有大型项目。的print报表打印在其上制作的节目相当慢性病了很多。

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

所以我的问题是如何将stdout重定向为空,即如何使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方法的类(不执行任何操作),然后将stdout重定向到该类的实例。

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

dp = DontPrint()
sys.stdout = dp

在python中有内置的机制吗?还是有比这更好的东西?



1
我刚刚发现了一个奇特的东西。尽管我不确定为什么将sys.stdout转换为None在我的程序中实际上是可行的。我在将编码重定向到os.devnull时遇到了非常奇怪的问题,因此我尝试仅使用None来工作,并且它可以正常工作。在Django单元测试中可能与我有关,但我不确定。
Teekin '18年

Answers:


233

跨平台:

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

然后如何取消呢?完成后,是否有办法重新打开打印语句?
jj172

4
当然,只需保存对原始文件的引用,sys.stdout然后再重新设置即可。例如old_stdout = sys.stdout,在其他任何代码之前,然后sys.stdout = old_stdout在完成时。
2014年

1
注意:它不会在文件描述符级别进行重定向,即,它可能无法重定向外部子进程的输出,即直接打印到C stdout的C扩展的输出os.write(1, b'abc\n')。您需要os.dup2()在文件描述符级别重定向,请参阅stdout_redirected()
jfs

4
请注意,这里是sys.__stdout__用于取消重定向的。因此,您只需要这样做,sys.stdout = sys.__stdout__而无需存储备份。
康斯坦丁·塞克雷什

28

这样做的一种好方法是创建一个用于包装打印内容的小型上下文处理器。然后,您可以使用with-statement来使所有输出静音。

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")

运行此代码仅显示输出的第二行,而不输出第一行:

$ python test.py
this will print

这可以跨平台(Windows + Linux + Mac OSX)运行,并且比其他解决方案更干净。


@celticminstrel您完全正确,感谢您纠正我。之后,我更新了代码以重置sys.stdout。
EmilStenström'16

这缺少一些错误检查,但却是个好主意
Mad Physicist

添加了代码以显示其在Python 3中的工作原理。
埃米尔·斯滕斯特罗姆(EmilStenström)

15

如果您使用的是python 3.4或更高版本,则可以使用标准库提供一种简单安全的解决方案:

import contextlib

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

3
with contextlib.redirect_stdout(None)作品也一样
克里斯·科格登

@ChrisCogdon很好的提示,我相应地编辑了答案。
iFreilicht

1
如果您使用的是pprint库,则无法使用。AttributeError: 'NoneType' object has no attribute 'write'
Speeeddy

@Speeeddy您是否在python 2中收到此错误?您可以使用write不执行任何操作的伪方法创建一个类。请参阅下面的答案。
dizcza

8

(至少在我的系统上)似乎写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

4
仅作记录,您下次想计时时,只需使用timeit
Antoine Pelisse 2015年

6

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

python myprogram.py > /dev/null

对于Windows:

python myprogram.py > nul

2
最好有一个适用于所有平台的解决方案。
Pushpak Dagade 2011年

2
@Guanidene,也许,但是如果他是唯一使用他的程序的人,他几乎可以保证环境。
尼克雷德福

nul = myfunc()
Hicsy

2

这个怎么样:

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(),然后在该函数运行完毕后恢复输出行为。

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

主要缺点是,这仅适用于Python 3.4和更高版本。



1

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

如果您使用的是* NIX,则可以执行sys.stdout = open('/dev/null'),但这比滚动自己的课程要轻巧。



0

你为什么不试试这个?

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

因为A)可能甚至无法正常工作,而B)如果可行,那么您将得到错误,而不仅仅是抑制输出。
疯狂物理学家

0
sys.stdout = None

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

在文档中有一个注释

在某些情况下,stdin,stdout和stderr以及原始值stdinstdoutstderr可以为None。对于未连接到控制台的Windows GUI应用程序以及以pythonw开头的Python应用程序,通常是这种情况。


在这种情况下,“确定”和“尝试打印时不会抛出错误”是完全不同的东西。
疯狂物理学家

1
你是对的。您不能使用调用任何方法,sys.stdout = Null因此在某些情况下可能很危险。
亚历山大·郑

在这种确切情况下,这是危险的。OP专门解决了他在执行此操作时遇到的错误。
疯狂物理学家

0

补充iFreilicht的答案 -适用于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!")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.