[英]Redirecting stdout to "nothing" in python
我有一个由足够多的模块组成的大型项目,每个模块都按照标准 output 打印一些东西。 现在随着项目规模的扩大,没有大的。 print
语句在标准输出上打印了很多,这使得程序相当慢。
所以,我现在想在运行时决定是否将任何内容打印到标准输出。 我无法对模块进行更改,因为它们有很多。 (我知道我可以将标准输出重定向到一个文件,但即使这样也相当慢。)
所以我的问题是如何将标准输出重定向到无,即如何使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.
目前我唯一的想法是制作一个 class,它有一个 write 方法(什么都不做),并将标准输出重定向到这个 class 的实例。
class DontPrint(object):
def write(*args): pass
dp = DontPrint()
sys.stdout = dp
python 中有内置机制吗? 或者还有什么比这更好的吗?
跨平台:
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
一个很好的方法是创建一个小型上下文处理器,将打印件包装在其中。然后,您只需在with
语句中使用 is 即可使所有 output 静音。
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。
运行此代码仅打印 output 的第二行,而不是第一行:
$ python test.py
this will print
这适用于跨平台(Windows + Linux + Mac OSX),并且比其他答案更干净。
如果您使用的是 python 3.4 或更高版本,则使用标准库有一个简单且安全的解决方案:
import contextlib
with contextlib.redirect_stdout(None):
print("This won't print!")
(至少在我的系统上)似乎写入 os.devnull 比写入 DontPrint class 快 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)
给出了以下 output:
<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
如果您在 Unix 环境(包括 Linux)中,您可以将 output 重定向到/dev/null
:
python myprogram.py > /dev/null
对于 Windows:
python myprogram.py > nul
这个怎么样:
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 模块中的功能来隐藏您尝试运行的任何命令的output ,具体取决于 should_hide_output should_hide_output()
的结果,然后在 ZC1C425268E68385D1 运行完成后恢复 output 行为。
如果要隐藏标准错误contextlib
,则从 contextlib 导入redirect_stderr
并添加一行stack.enter_context(redirect_stderr(null_stream))
。
主要缺点是这只适用于 Python 3.4 及更高版本。
sys.stdout = None
print()
的情况是可以的。 但是如果你调用 sys.stdout 的任何方法,例如sys.stdout.write()
,它可能会导致错误。
在某些情况下,stdin、stdout 和 stderr 以及原始值stdin 、 stdout和stderr可以为 None。 未连接到控制台的 Windows GUI 应用程序和使用 pythonw 启动的 Python 应用程序通常是这种情况。
你可以嘲笑它。
import mock
sys.stdout = mock.MagicMock()
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!")
您的 class 可以正常工作(除了write()
方法名称 - 它需要称为write()
,小写)。 只需确保将sys.stdout
的副本保存在另一个变量中即可。
如果你在 *NIX 上,你可以做sys.stdout = open('/dev/null')
,但这比滚动你自己的 class 更不便携。
流程中有许多好的答案,但这是我的 Python 3 答案(当不再支持 sys.stdout.fileno() 时):
import os
import sys
oldstdout = os.dup(1)
oldstderr = os.dup(2)
oldsysstdout = sys.stdout
oldsysstderr = sys.stderr
# Cancel all stdout outputs (will be lost) - optionally also cancel stderr
def cancel_stdout(stderr=False):
sys.stdout.flush()
devnull = open('/dev/null', 'w')
os.dup2(devnull.fileno(), 1)
sys.stdout = devnull
if stderr:
os.dup2(devnull.fileno(), 2)
sys.stderr = devnull
# Redirect all stdout outputs to a file - optionally also redirect stderr
def reroute_stdout(filepath, stderr=False):
sys.stdout.flush()
file = open(filepath, 'w')
os.dup2(file.fileno(), 1)
sys.stdout = file
if stderr:
os.dup2(file.fileno(), 2)
sys.stderr = file
# Restores stdout to default - and stderr
def restore_stdout():
sys.stdout.flush()
sys.stdout.close()
os.dup2(oldstdout, 1)
os.dup2(oldstderr, 2)
sys.stdout = oldsysstdout
sys.stderr = oldsysstderr
要使用它:
使用以下命令取消所有 stdout 和 stderr 输出:
取消标准输出(标准错误=真)
将所有标准输出(但不是标准错误)路由到一个文件:
reroute_stdout('output.txt')
要恢复标准输出和标准错误:
恢复标准输出()
你为什么不试试这个?
sys.stdout.close()
sys.stderr.close()
将在此处为众多答案添加一些示例:
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()
正常的 output 将是:
>python TEST.py
usage: TEST.py [-h] -p PARAM
TEST.py: error: the following arguments are required: -p/--param
如果您不想处理资源分配或滚动您自己的 class,您可能需要使用来自TextIO
类型的 TextIO。 默认情况下,它为您提供了所有必需的方法。
import sys
from typing import TextIO
sys.stdout = TextIO()
我用这个。 将stdout
重定向到一个字符串,您随后会忽略该字符串。 我使用上下文管理器来保存和恢复stdout
的原始设置。
from io import StringIO
...
with StringIO() as out:
with stdout_redirected(out):
# Do your thing
其中stdout_redirected
定义为:
from contextlib import contextmanager
@contextmanager
def stdout_redirected(new_stdout):
save_stdout = sys.stdout
sys.stdout = new_stdout
try:
yield None
finally:
sys.stdout = save_stdout
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.