Подавлять вызовы на печать (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) репутации, чтобы сделать это.