How to block calls to print?

116,703

Solution 1

Python lets you overwrite standard output (stdout) with any file object. This should work cross platform and write to the null device.

import sys, os

# Disable
def blockPrint():
    sys.stdout = open(os.devnull, 'w')

# Restore
def enablePrint():
    sys.stdout = sys.__stdout__


print 'This will print'

blockPrint()
print "This won't"

enablePrint()
print "This will too"

If you don't want that one function to print, call blockPrint() before it, and enablePrint() when you want it to continue. If you want to disable all printing, start blocking at the top of the file.

Solution 2

Use with

Based on @FakeRainBrigand solution I'm suggesting a safer solution:

import os, sys

class HiddenPrints:
    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w')

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.stdout.close()
        sys.stdout = self._original_stdout

Then you can use it like this:

with HiddenPrints():
    print("This will not be printed")

print("This will be printed as before")

This is much safer because you can not forget to re-enable stdout, which is especially critical when handling exceptions.

Without with — Bad practice

The following example uses enable/disable prints functions that were suggested in previous answer.

Imagine that there is a code that may raise an exception. We had to use finally statement in order to enable prints in any case.

try:
    disable_prints()
    something_throwing()
    enable_prints() # This will not help in case of exception
except ValueError as err:
    handle_error(err)
finally:
    enable_prints() # That's where it needs to go.

If you forgot the finally clause, none of your print calls would print anything anymore.

It is safer to use the with statement, which makes sure that prints will be reenabled.

Note: It is not safe to use sys.stdout = None, because someone could call methods like sys.stdout.write()

Solution 3

As @Alexander Chzhen suggested, using a context manager would be safer than calling a pair of state-changing functions.

However, you don't need to reimplement the context manager - it's already in the standard library. You can redirect stdout (the file object that print uses) with contextlib.redirect_stdout, and also stderr with contextlib.redirect_stderr.

import os
import contextlib

with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
    print("This won't be printed.")

Solution 4

If you want to block print calls made by a particular function, there is a neater solution using decorators. Define the following decorator:

# decorater used to block function printing to the console
def blockPrinting(func):
    def func_wrapper(*args, **kwargs):
        # block all printing to the console
        sys.stdout = open(os.devnull, 'w')
        # call the method in question
        value = func(*args, **kwargs)
        # enable all printing to the console
        sys.stdout = sys.__stdout__
        # pass the return value of the method back
        return value

    return func_wrapper

Then just place @blockPrinting before any function. For example:

# This will print
def helloWorld():
    print("Hello World!")
helloWorld()

# This will not print
@blockPrinting
def helloWorld2():
    print("Hello World!")
helloWorld2()

Solution 5

If you are using Jupyter Notebook or Colab use this:

from IPython.utils import io

with io.capture_output() as captured:
    print("I will not be printed.")
Share:
116,703

Related videos on Youtube

dmlicht
Author by

dmlicht

I'm a programmer, musician, perpetual backpacker, and kindergarten teacher. I love tea, hiking, biking, and learning.

Updated on April 22, 2022

Comments

  • dmlicht
    dmlicht about 2 years

    Is there a way to stop a function from calling print?


    I am using the pygame.joystick module for a game I am working on.

    I created a pygame.joystick.Joystick object and in the actual loop of the game call its member function get_button to check for user input. The function does everything I need it to do, but the problem is that it also calls print, which slows down the game considerably.

    Can I block this call to print?

    • Davis Herring
      Davis Herring almost 3 years
      This ought to be considered a bug in the module in question (perhaps long since fixed, of course). Libraries have no business writing to the standard streams except on request.
  • iFreilicht
    iFreilicht over 6 years
    Very good solution! I just wrote the same thing and then found you already answered that way :D I'll add a bit of information about why this is a better way to do it.
  • jlsecrest
    jlsecrest over 6 years
    Noobie question here: Would it be important to close() devnull after exiting the class?
  • Alexander C
    Alexander C over 6 years
    @Wadsworth, I don't know the answer. I guess devnull's properties do not require it to be closed properly. But rumors say that you should always close open handlers to release resources. CPython as I know should close devnull itself as far as garbage collector get it.
  • WellDone2094
    WellDone2094 over 6 years
    I was getting ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'> when using this code, solved it by setting sys.stdout = None instead of open(os.devnull,'w')
  • Johnny V
    Johnny V over 6 years
    This seems to have permanently blocked print for me. enablePrint does not restore it
  • oski86
    oski86 almost 5 years
    This solution won't restore properly printing to the Jupyter cells
  • Radio Controlled
    Radio Controlled almost 5 years
    I guess the argument to print is still evaluated, so it will take longer than the script with all print lines manually commented out?
  • Alexander C
    Alexander C about 4 years
    @WellDone2094, thanks. I've added sys.stdout.close() to the exit method. This should help. Note that sys.stdout = None may cause an error, because someone may call stdout's methods like sys.stdout.write().
  • Syed Md Ismail
    Syed Md Ismail over 3 years
    My function processes successfully if I don't use with HiddenPrints(). When I use it throws an error "UnicodeEncodeError: 'charmap' codec can't encode character '\u017c' in position 204: character maps to <undefined>"
  • Alexander C
    Alexander C over 3 years
    @SyedMdIsmail I think you should check what line causes error exactly. You may have some logger attached or, who knows, maybe you have replaced original print function with another implementation.
  • PascalIv
    PascalIv about 3 years
    Does not work for me! Function is still printing...
  • ForgottenUmbrella
    ForgottenUmbrella about 3 years
    @PascalIv What exactly did you try? Still works for me in Python 3.9 on Linux.
  • PascalIv
    PascalIv about 3 years
    I realized it's because I am using Colab. But I got it to work with from IPython.utils import io with io.capture_output() as captured: print("I will not be printed.")
  • IljaBek
    IljaBek about 3 years
    for Jupyter you can monkey-patch-save the original stdout in sys as sys._jupyter_stdout = sys.stdout in blockPrint and restore to it in enablePrint
  • xelf
    xelf about 3 years
    The example I listed does work, but if you have an example where you have tried something similar and it did not work for you, you will have to be more explicit about what you tried and what changes you made. What version of Python were you using?
  • SurpriseDog
    SurpriseDog about 3 years
    This is extremely useful for debugging. Why didn't I see this before?
  • Admin
    Admin over 2 years
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
  • Alex Peters
    Alex Peters about 2 years
    I like the idea, but it only worked for me if I dealt with __builtins__.print specifically.
  • Guillaume
    Guillaume about 2 years
    for me, this used to work in Python 3.7, but moving to 3.9 no longer works
  • ForgottenUmbrella
    ForgottenUmbrella about 2 years
    @Guillaume works for me on Python 3.10.4 on Linux. It also worked for me on Python 3.9 last time someone raised an issue with it, as evident in a previous comment. You're going to need to provide more context.
  • Guillaume
    Guillaume about 2 years
    I have created a question for it, because maybe it is related to AWS Lambda then? on my Mac with Python 3.9, simply doing logger.removeHandler(sys.stdout) is enough, but somehow the Lambda/CloudWatch still prints everything! See stackoverflow.com/questions/72389347/…