如何阻止打印呼叫?


79

有没有一种方法可以阻止函数调用print


我正在将pygame.joystick模块用于正在开发的游戏。

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

我可以阻止此呼叫print吗?

Answers:


104

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()希望其继续执行时调用。如果要禁用所有打印,请在文件顶部开始阻止。


22
这似乎已经永久性地阻止了我的打印。enablePrint不会恢复它
约翰尼V

10
此解决方案无法正确恢复到Jupyter单元的打印
oski86 '19

1
我猜想print的参数仍在计算中,所以它将花费比脚本所有手动注释掉的打印行更长的时间?
无线电控制的

77

基于@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在任何情况下,我们都必须使用statement来启用打印。

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()


6
很好的解决方案!我只是写了同样的东西,然后发现您已经用这种方式回答了:D我将添加一些信息,说明为什么这是一种更好的方法。
iFreilicht

Noobie的问题在这里:退出课程后close()devnull是否重要?
jlsecrest

@Wadsworth,我不知道答案。我猜devnull的属性不要求它正确关闭。但是有传言说,您应该始终关闭打开的处理程序以释放资源。据我所知,CPython应该关闭devnull本身,直到垃圾回收器将其关闭。
Alexander Chzhen

2
ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>在使用此代码时遇到问题,通过设置sys.stdout = None而不是open(os.devnull,'w')来解决它
WellDone2094 '18

@ WellDone2094,谢谢。我已经添加sys.stdout.close()了退出方法。这应该有所帮助。请注意,这sys.stdout = None可能会导致错误,因为有人可能会调用stdout的方法sys.stdout.write()
Alexander Chzhen

28

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

但是,您不需要重新实现上下文管理器-它已经在标准库中。您可以重定向stdout(文件对象print与使用)contextlib.redirect_stdout,也stderrcontextlib.redirect_stderr

import os
import contextlib

with open(os.devnull, "w") as f, contextlib.redirect_stdout(f):
    print("This won't be printed.")

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()

2

不,没有,尤其是大多数PyGame是用C编写的。

但是,如果此函数调用print,则是PyGame错误,您应该报告它。


2

我遇到了同样的问题,我没有找到其他解决方案,而是将程序的输出(我不完全知道垃圾邮件是在stdout还是stderr上重定向)到/dev/null必杀技。

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

编辑:

pygame.joystick模块printf在所有将实际值返回给Python的函数中都有对的调用:

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

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


2

完全不同的方法是在命令行重定向。如果您使用的是Windows,则表示批处理脚本。在Linux上,bash。

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

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


1

我用来打印的模块stderr。因此,这种情况下的解决方案是:

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

1

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

我希望我可以将我的解决方案添加到Alexander的回答下面作为评论,但是我没有足够的(50)名声。


0

您可以执行简单的重定向,这似乎比使用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库,并将其自身的输出输出到stdout,或者您正在使用intput()。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.