如何阻止打印调用?

有没有办法阻止函数调用 print


我使用的 pygame.joystick模块的一个游戏,我的工作。

我创建了一个 pygame.joystick.Joystick对象,在游戏的实际循环中调用它的成员函数 get_button来检查用户输入。该函数完成了我需要它做的所有事情,但问题是它还调用了 print,这大大降低了游戏的速度。

我能打这个电话到 print吗?

135492 次浏览

不,没有,尤其是大部分 PyGame 都是用 C 编写的。

但是如果这个函数调用 print,那么它就是 PyGame 错误,您应该直接报告它。

我也遇到过同样的问题,我没有找到另一个解决方案,而是将程序的输出重定向到 /dev/null的极乐世界(我不知道垃圾邮件是发生在 stdout 还是 stderr 上)。

事实上,它是开源的,但是我没有足够的热情去深入研究 pygame源代码-和构建过程-以某种方式停止调试垃圾邮件。

编辑:

The pygame.joystick module has calls to printf in all functions that return the actual values to Python:

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

不幸的是,您需要将这些注释掉并重新编译整个过程。也许提供的 setup.py会使这比我想象的容易。你可以试试这个。

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()。如果要禁用 所有打印,请从文件顶部开始阻塞。

另一种完全不同的方法是在命令行上重定向。如果你在 Windows 上,这意味着一个批处理脚本。在 Linux 上 bash。

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

除非您要处理多个进程,否则这个 应该是可以工作的。对于 Windows 用户,这可能是您正在创建的快捷方式(开始菜单/桌面)。

我用来打印到 stderr的模块,所以在这种情况下的解决方案是:

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

使用 with

基于@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")

这样更安全,因为您不能忘记重新启用 stdout,这在处理异常时尤其关键。

Without with — Bad practice

下面的示例使用上一个答案中建议的启用/禁用打印函数。

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.

使用 with语句更加安全,这样可以确保重新启用打印。

注意: 使用 sys.stdout = None是不安全的,因为有人可能会调用像 sys.stdout.write()这样的方法

正如@Alexander Chchen 所建议的,使用上下文管理器比调用一对状态变化函数更安全。

但是,您不需要重新实现上下文管理器——它已经在标准库中了。可以用 contextlib.redirect_stdout重定向 stdout(print使用的文件对象) ,也可以用 contextlib.redirect_stderr重定向 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
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()

基于@Alexander Chchen 的解决方案,我在这里介绍了如何将其应用到一个函数上,该函数具有是否禁止打印的选项。

    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)名声这样做。

您可以执行一个简单的重定向,这似乎比使用 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 ()函数,如果调用其他产生输出的函数,则不会禁用所有输出。例如,如果您正在调用一个生成自己的输出到 stdout 的 C 库,或者如果您正在使用 intput ()。

如果你正在使用木星笔记本或 Colab 使用这个:

from IPython.utils import io


with io.capture_output() as captured:
print("I will not be printed.")
"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

https://stackoverflow.com/a/27622201

更改 print ()函数的 file 对象值。默认情况下它是 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)

如果希望使用变量启用/禁用 print,可以调用辅助函数而不是 print,比如 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()

使用上述其中一个“安全”启用/禁用函数对