Подавлять вызовы на печать (python)

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


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

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

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

Ответ 1

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(), когда вы хотите продолжить. Если вы хотите отключить всю печать, начните блокировку в верхней части файла.

Ответ 2

На основе решения @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 where it needs to go.

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

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

Ответ 3

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

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

Ответ 4

Как предположил @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.")

Ответ 5

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

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

EDIT:

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

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

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

Ответ 6

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

# 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

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

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

    import os, sys
    class SuppressPrints:
        #different from Alexander 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) репутации, чтобы сделать это.