Подавить звонки на печать (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
Модуль, который я использовал для печати 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()
с помощью одной из вышеперечисленных «безопасных» парных функций включения/отключения