37

Well, the headline seems to me sufficient. I use some function that at some points print something in the console. As I can't modify them, I would like to know if there is a solution to not printing while using these functions.

Thanks a lot !

Nico

NicoCati
  • 527
  • 1
  • 8
  • 11
  • 1
    What's the `batch console`? Are you talking about `stdout`? – MattH Dec 09 '11 at 14:50
  • That's a sign of bad design. If possible, fix the function. Otherwise, if the function is using Python's `print`, you could temporarily replace `sys.stdout` with an object with an empty `write` method. – yak Dec 09 '11 at 15:02

6 Answers6

44

Yes, you can redirect sys.stdout:

import sys
import os

old_stdout = sys.stdout # backup current stdout
sys.stdout = open(os.devnull, "w")

my_nasty_function()

sys.stdout = old_stdout # reset old stdout

Just replace my_nasty_function with your actual function.

EDIT: Now should work on windows aswell.

EDIT: Use backup variable to reset stdout is better when someone wraps your function again

Noctua
  • 5,058
  • 1
  • 18
  • 23
Constantinius
  • 34,183
  • 8
  • 77
  • 85
  • 1
    There's no need for `backup_stdout`, as you can use `sys.stdout = sys.__stdout__` to restore the original (see [here](http://docs.python.org/library/sys.html#sys.__stdout__)). Also, it would be better to use [`os.devnull`](http://docs.python.org/library/os.html#os.devnull), so that it will work on Windows. – ekhumoro Dec 09 '11 at 15:07
  • 4
    @ekhumoro `backup_stdout` is a better solution since your code can be treated by the caller with similar measures :) I mean, *restoring* `stdout` should actually *restore* the initial value, and not *set* it to something arbitrary. – Janusz Lenar Jul 05 '13 at 09:48
  • What are the hazards if the nasty function throws an error? I want to know how this should be modified to be production-ready. – AlanSE Jul 30 '18 at 14:34
  • @AlanSE You can wrap the `my_nasty_function()` in a `try/finally` block (put the resetting of the `stdout` (`sys.stdout = sys.__stdout__ `) in the finally, and you should be good to go. – Constantinius Jul 31 '18 at 09:24
9

Constantinius' answer answer is ok, however there is no need to actually open null device. And BTW, if you want portable null device, there is os.devnull.

Actually, all you need is a class which will ignore whatever you write to it. So more portable version would be:

class NullIO(StringIO):
    def write(self, txt):
       pass

sys.stdout = NullIO()

my_nasty_function()

sys.stdout = sys.__stdout__

.

Community
  • 1
  • 1
vartec
  • 131,205
  • 36
  • 218
  • 244
7

Another option would be to wrap your function in a decorator.

from contextlib import redirect_stdout
from io import StringIO 

class NullIO(StringIO):
    def write(self, txt):
        pass


def silent(fn):
    """Decorator to silence functions."""
    def silent_fn(*args, **kwargs):
        with redirect_stdout(NullIO()):
            return fn(*args, **kwargs)
    return silent_fn


def nasty():
    """Useful function with nasty prints."""
    print('a lot of annoying output')
    return 42


# Wrap in decorator to prevent printing.
silent_nasty = silent(nasty)
# Same output, but prints only once.
print(nasty(), silent_nasty())
Jarno
  • 6,243
  • 3
  • 42
  • 57
2

You could use a modified version of this answer to create a "null" output context to wrap the call the function in.

That can be done by just passing os.devnull as the new_stdout argument to the stdout_redirected() context manager function when it's used.

Tonechas
  • 13,398
  • 16
  • 46
  • 80
martineau
  • 119,623
  • 25
  • 170
  • 301
1

The currently accepted answer by Constantinius works great in most circumstances, but not in Jupyter notebooks. Here's how to get it to work (with a reusable function)...

TLDR~Instead of using sys.__stout__, backup sys.stdout and restore it later on.

In a Jupyter notebook, running sys.stdout == sys.__stdout__ returns false. This is because each cell has a separate output stream (instead of the one terminal instance, which is sys.__stdout__). So for everyone working with Jupyter notebooks, make sure to back up the old sys.stdout path and restore it afterwards. Here's a function for it:

import sys, os
def deafen(function, *args):
    real_stdout = sys.stdout
    sys.stdout = open(os.devnull, "w")
    output = function(*args)
    sys.stdout = real_stdout
    return output

Pass to deafen a function along with its arguments/parameters (args). It backs up the old sys.stdout, switches to os.devnull and back again itself.

For a complete example we can create a second function (test_function):

def test_function(first_argument, second_argument, *args):
    print(first_argument)
    print(second_argument)
    print(args)

Now if we try using the test_function like normal (a.k.a. without deafen) we will get a bunch of output printed onto the screen:

print("Printing should work fine here")
test_function(32, 12, 1, 32, 1)

However, when using deafen, we'll get no new output:

print("That'll be the last thing you see...")
deafen(test_function, 32, 12, 1, 32, 1)

On a side note, the deafen function still returns a functions output. You can also use deafen with sys.__stdout__ by replacing sys.stdout = real_stdout with sys.stdout = sys.__stdout__ (and may as well remove real_stdout = sys.stdout whilst you're at it).

Hope that helps anyone who is looking for a slightly more robust or flexible solution (likely for Jupyter notebooks, or use with multiple functions)!

1

Constantinius' solution will work on *nix, but this should work on any platform:

import sys
import tempfile

sys.stdout = tempfile.TemporaryFile()

# Do crazy stuff here

sys.stdout.close()
#now the temp file is gone
sys.stdout = sys.__stdout__
dtanders
  • 1,835
  • 11
  • 13