如何阻止打印呼叫?
- 2025-02-21 08:48:00
- admin 原创
- 27
问题描述:
有没有办法阻止函数调用print
?
我正在使用该pygame.joystick
模块开发一款游戏。
我创建了一个pygame.joystick.Joystick
对象,并在游戏的实际循环中调用其成员函数get_button
来检查用户输入。该函数完成了我需要它做的所有事情,但问题是它还调用了print
,这大大降低了游戏速度。
我可以屏蔽这个来电吗print
?
解决方案 1:
使用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,这在处理异常时尤其重要。
不好的做法:没有with
以下示例使用上一个答案中建议的启用/禁用打印功能。
假设有一段代码可能会引发异常。finally
无论如何,我们都必须使用语句才能启用打印。
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.
如果您忘记了该finally
条款,您的任何print
通话都不会再打印任何内容。
使用该with
语句更加安全,它可以确保重新启用打印。
注意:使用这种方法并不安全sys.stdout = None
,因为有人可能会调用类似的方法sys.stdout.write()
解决方案 2:
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()
希望其继续时调用。如果您想要禁用所有打印,请在文件顶部开始阻止。
解决方案 3:
正如@Alexander Chzhen 所建议的,使用上下文管理器比调用一对状态改变函数更安全。
但是,您不需要重新实现上下文管理器 - 它已经在标准库中了。您可以使用重定向(使用的文件对象) ,也可以使用重定向stdout
(使用的文件对象) 。print
`contextlib.redirect_stdoutstderr
contextlib.redirect_stderr`
import os
import contextlib
with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
print("This won't be printed.")
您可以通过定义自己的包装器上下文管理器来封装这个逻辑:
import os
import contextlib
@contextlib.contextmanager
def suppress_print():
with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
yield
print("This will be printed")
with suppress_print():
print("This will not")
print("Printing works outside the with-statement")
解决方案 4:
如果要阻止特定函数的打印调用,则可以使用装饰器来提供更简洁的解决方案。定义以下装饰器:
# 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()
您Jupyter Notebooks
可能需要将func_wrapper
代码替换为:
from IPython.utils.io import capture_output
def func_wrapper(*args, **kwargs):
with capture_output():
value = func(*args, **kwargs)
return value
解决方案 5:
如果你正在使用 Jupyter Notebook 或 Colab,请使用以下命令:
from IPython.utils import io
with io.capture_output() as captured:
print("I will not be printed.")
解决方案 6:
完全不同的方法是在命令行上重定向。如果你使用的是 Windows,这意味着批处理脚本。在 Linux 上,则是 bash。
/full/path/to/my/game/game.py > /dev/null
C:FullPathToMyGame.exe > nul
除非您正在处理多个进程,否则这应该可行。对于 Windows 用户,这可能是您正在创建的快捷方式(开始菜单/桌面)。
解决方案 7:
您可以进行一个简单的重定向,这看起来比弄乱标准输出要安全得多,并且不会引入任何额外的库。
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 库,而该库会向 stdout 产生自己的输出,或者您正在使用 intput()。
解决方案 8:
我遇到了同样的问题,我没有找到其他解决方案,而是将程序的输出(我不知道垃圾邮件是发生在 stdout 还是 stderr 上)重定向到/dev/null
nirvana。
确实,它是开源的,但我没有足够的热情去深入pygame
研究源代码和构建过程,以某种方式阻止调试垃圾邮件。
编辑 :
该pygame.joystick
模块在所有函数中都调用了printf
将实际值返回给 Python:
printf("SDL_JoystickGetButton value:%d:
", value);
不幸的是,您需要注释掉这些内容并重新编译整个内容。也许提供的内容setup.py
会比我想象的更容易。您可以尝试这个...
解决方案 9:
不,没有,尤其是 PyGame 的大部分都是用 C 编写的。
但是如果此函数调用了 print,那么它就是 PyGame 错误,你应该报告它。
解决方案 10:
"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
解决方案 11:
更改 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)
解决方案 12:
我使用的模块打印到stderr
。因此,在这种情况下,解决方案是:
sys.stderr = open(os.devnull, 'w')
解决方案 13:
基于@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)来这样做。
解决方案 14:
如果您想使用变量启用/禁用打印,您可以调用辅助函数来代替打印,例如 printe(此名称只是为了方便)
def printe(*what_to_print):
if prints_enable:
string = ""
for items in what_to_print:
string += str(items) + " "
print(string)
解决方案 15:
定义一个新的打印函数,首先启用打印,然后打印输出,然后再次禁用打印。
def Print (*output):
enablePrint()
print (output)
disablePrint()
使用上述“安全”启用/禁用功能之一