Silence the stdout of a function in Python without trashing sys.stdout and restoring each function call
Assigning the stdout
variable as you're doing has no effect whatsoever, assuming foo
contains print
statements -- yet another example of why you should never import stuff from inside a module (as you're doing here), but always a module as a whole (then use qualified names). The copy
is irrelevant, by the way. The correct equivalent of your snippet is:
import sys
save_stdout = sys.stdout
sys.stdout = open('trash', 'w')
foo()
sys.stdout = save_stdout
Now, when the code is correct, is the time to make it more elegant or fast. For example, you could use an in-memory file-like object instead of file 'trash':
import sys
import io
save_stdout = sys.stdout
sys.stdout = io.BytesIO()
foo()
sys.stdout = save_stdout
for elegance, a context is best, e.g:
import contextlib
import io
import sys
@contextlib.contextmanager
def nostdout():
save_stdout = sys.stdout
sys.stdout = io.BytesIO()
yield
sys.stdout = save_stdout
once you have defined this context, for any block in which you don't want a stdout,
with nostdout():
foo()
More optimization: you just need to replace sys.stdout with an object that has a no-op write
method. For example:
import contextlib
import sys
class DummyFile(object):
def write(self, x): pass
@contextlib.contextmanager
def nostdout():
save_stdout = sys.stdout
sys.stdout = DummyFile()
yield
sys.stdout = save_stdout
to be used the same way as the previous implementation of nostdout
. I don't think it gets any cleaner or faster than this;-).
Just to add to what others already said, Python 3.4 introduced the contextlib.redirect_stdout
context manager. It accepts a file(-like) object to which the output is to be redirected.
Redirecting to /dev/null will suppress the output:
In [11]: def f(): print('noise')
In [12]: import os, contextlib
In [13]: with open(os.devnull, 'w') as devnull:
....: with contextlib.redirect_stdout(devnull):
....: f()
....:
In [14]:
This solution can be adapted to be used as a decorator:
import os, contextlib
def supress_stdout(func):
def wrapper(*a, **ka):
with open(os.devnull, 'w') as devnull:
with contextlib.redirect_stdout(devnull):
return func(*a, **ka)
return wrapper
@supress_stdout
def f():
print('noise')
f() # nothing is printed
Another possible and occasionally useful solution that will work in both Python 2 and 3 is to pass /dev/null as an argument to f
and redirect the output using the file
argument of the print
function:
In [14]: def f(target): print('noise', file=target)
In [15]: with open(os.devnull, 'w') as devnull:
....: f(target=devnull)
....:
In [16]:
You can even make target
completely optional:
def f(target=sys.stdout):
# Here goes the function definition
Note, you'll need to
from __future__ import print_function
in Python 2.
Chiming in very late to this with what I thought was a cleaner solution to this problem.
import sys, traceback
class Suppressor(object):
def __enter__(self):
self.stdout = sys.stdout
sys.stdout = self
def __exit__(self, type, value, traceback):
sys.stdout = self.stdout
if type is not None:
# Do normal exception handling
def write(self, x): pass
Usage:
with Suppressor():
DoMyFunction(*args,**kwargs)
Why do you think this is inefficient? Did you test it? By the way, it does not work at all because you are using the from ... import
statement.
Replacing sys.stdout
is fine, but don't make a copy and don't use a temporary file. Open the null device instead:
import sys
import os
def foo():
print "abc"
old_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
try:
foo()
finally:
sys.stdout.close()
sys.stdout = old_stdout
redirect_stdout() has been added to contextlib since python 3.4
For python >= 3.4, this should do it:
import contextlib
import io
with contextlib.redirect_stdout(io.StringIO()):
foo()