Подавить звонки на печать (python)

Есть ли способ, чтобы остановить функцию от вызова print?


Я использую pygame.joystick модуль для игры, над которой я работаю.

Я создал pygame.joystick.Joystick объект и в реальном цикле игры вызвать его функцию-член get_button проверить пользовательский ввод. Функция делает все, что мне нужно, но проблема в том, что она также вызывает print, что значительно замедляет игру.

Могу ли я заблокировать этот звонок print?

15 ответов

Python позволяет перезаписывать стандартный вывод (stdout) любым файловым объектом. Это должно работать кроссплатформенно и записывать на нулевое устройство.

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"

Если вы не хотите, чтобы эта функция печаталась, вызовите blockPrint() перед этим и enablePrint() когда вы хотите, чтобы это продолжалось. Если вы хотите отключить всю печать, начните блокировку в верхней части файла.

На основе решения @FakeRainBrigand я предлагаю более безопасное решение:

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

Тогда вы можете использовать это так:

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

print("This will be printed as before")

Это намного безопаснее, потому что вы не можете забыть снова включить стандартный вывод, что особенно важно при обработке исключений.

# This is an example of not-so-good solution
# without 'with' context manager statement.
try:
    disable_prints()
    something_throwing()
    # enable_prints() This wouldn't be enough!
except ValueError:
    handle_error()
finally:
    enable_prints() # That's where it needs to go.

Если вы забыли finally оговорка, никто из ваших print звонки будут печатать что-нибудь больше. С использованием with Заявление, что не может произойти.

Это не безопасно использовать sys.stdout = Noneпотому что кто-то может вызвать методы, такие как sys.stdout.write()

Как предположил @Alexander Chzhen, использование диспетчера контекста было бы безопаснее, чем вызов пары функций, изменяющих состояние.

Однако вам не нужно переопределять менеджер контекста - он уже есть в стандартной библиотеке. Вы можете перенаправить stdout (объект файла, который print использует) с contextlib.redirect_stdout, а также stderr с contextlib.redirect_stderr,

import os
import contextlib

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

Если вы хотите заблокировать вызовы печати, сделанные определенной функцией, есть более подходящее решение с использованием декораторов. Определите следующий декоратор:

# 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
        func(*args, **kwargs)
        # enable all printing to the console
        sys.stdout = sys.__stdout__

    return func_wrapper

Тогда просто место @blockPrinting перед любой функцией. Например:

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

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

Если вы используете Jupyter Notebook или Colab, используйте это:

      from IPython.utils import io

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

Нет, нет, тем более что большинство PyGame написано на C.

Но если эта функция вызывает print, то это ошибка PyGame, и вы должны просто сообщить об этом.

Вы можете сделать простое перенаправление, это кажется намного безопаснее, чем возиться с stdout, и не требует дополнительных библиотек.

enable_print  = print
disable_print = lambda *x, **y: None

print = disable_print
function_that_has_print_in_it(1)  # nothing is printed

print = enable_print
function_that_has_print_in_it(2)  # printing works again!

Примечание: это работает только для отключения функции print() и не отключит весь вывод, если вы вызываете что-то еще, что производит вывод. Например, если вы вызывали библиотеку C, которая выводила свой собственный вывод на стандартный вывод, или если вы использовали intput().

Совершенно другой подход будет перенаправление в командной строке. Если вы работаете в Windows, это означает пакетный скрипт. В Linux, Bash.

/full/path/to/my/game/game.py > /dev/null
C:\Full\Path\To\My\Game.exe > nul

Если вы не имеете дело с несколькими процессами, это должно работать. Для пользователей Windows это могут быть ярлыки, которые вы создаете (меню Пуск / Рабочий стол).

У меня была такая же проблема, и я не пришел к другому решению, кроме как перенаправить вывод программы (я точно не знаю, происходит ли рассылка спама на stdout или stderr) /dev/null нирвана.

Действительно, это открытый исходный код, но я не был достаточно страстным, чтобы погрузиться в pygame исходники - и процесс сборки - чтобы как-то остановить отладочный спам.

РЕДАКТИРОВАТЬ:

pygame.joystick модуль имеет вызовы printf во всех функциях, которые возвращают фактические значения в Python:

printf("SDL_JoystickGetButton value:%d:\n", value);

К сожалению, вам нужно закомментировать их и перекомпилировать все это. Может быть, при условии setup.py сделает это проще, чем я думал. Вы можете попробовать это...

      "stop a function from calling print"
# import builtins
# import __builtin__ # python2, not test
printenabled = False
def decorator(func):
    def new_func(*args,**kwargs):
        if printenabled:
            func("print:",*args,**kwargs)
    return new_func
print = decorator(print) # current file
# builtins.print = decorator(builtins.print)  # all files
# __builtin__.print = decorator(__builtin__.print) # python2

import sys
import xxxxx
def main():
    global printenabled
    printenabled = True
    print("1 True");
    printenabled = False
    print("2 False");
    printenabled = True
    print("3 True");
    printenabled = False
    print("4 False");
if __name__ == '__main__':
    sys.exit(main())

#output
print: 1 True
print: 3 True

/questions/5125680/kak-peregruzit-funktsiyu-pechati-chtobyi-rasshirit-ee-funktsionalnost/5125688#5125688

Модуль, который я использовал для печати stderr, Таким образом, решение в этом случае будет:

sys.stdout = open(os.devnull, 'w')

Основываясь на решении @Alexander Chzhen, я представляю здесь, как применить его к функции с возможностью подавления печати или нет.

    import os, sys
    class SuppressPrints:
        #different from Alexander`s answer
        def __init__(self, suppress=True):
            self.suppress = suppress

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

        def __exit__(self, exc_type, exc_val, exc_tb):
            if self.suppress:
                sys.stdout.close()
                sys.stdout = self._original_stdout
    #implementation
    def foo(suppress=True):
        with SuppressPrints(suppress):
            print("It will be printed, or not")

    foo(True)  #it will not be printed
    foo(False) #it will be printed

Я надеюсь, что я могу добавить свое решение ниже ответ Александра в качестве комментария, но у меня недостаточно (50) репутации, чтобы сделать это.

Изменить значение файлового объекта функции print(). По умолчанию это sys.stdout, вместо этого мы можем записать в нулевое устройство с помощью open(os.devnull, 'w')

      import os, sys

mode = 'debug' #'prod'

if mode == 'debug':
    fileobj = sys.stdout
else:
    fileobj = open(os.devnull,'w')

print('Hello Stackoverflow', file = fileobj)

Если вы хотите включить/отключить печать с помощью переменной, вы можете вместо печати вызвать вспомогательную функцию, что-то вроде printe (название просто для удобства)

      def printe(*what_to_print):
if prints_enable:
    string = ""
    for items in what_to_print:
        string += str(items) + " "
    print(string)

Определите новую функцию печати, в которой вы сначала включите печать. распечатайте свой вывод дальше. А затем снова отключить печать.

      def Print (*output):
   enablePrint()
   print (output)
   disablePrint()

с помощью одной из вышеперечисленных «безопасных» парных функций включения/отключения

Другие вопросы по тегам