ti-enxame.com

Suprimir chamadas para imprimir (python)

Existe uma maneira de parar uma função de chamar print?


Eu estou usando o pygame.joystick module para um jogo que estou trabalhando.

Criei um objeto pygame.joystick.Joystick e, no loop real do jogo, chame sua função-membro get_button para verificar a entrada do usuário. A função faz tudo que eu preciso, mas o problema é que ela também chama print, o que atrasa consideravelmente o jogo. 

Posso bloquear esta chamada para print?

39
dmlicht

O Python permite que você sobrescreva a saída padrão (stdout) com qualquer objeto de arquivo. Isso deve funcionar entre plataformas e gravar no dispositivo nulo.

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"

Se você não quiser que uma função seja impressa, chame blockPrint() antes dela e enablePrint() quando quiser que ela continue. Se você quiser desativar all printing, inicie o bloqueio na parte superior do arquivo.

53
FakeRainBrigand

Com base na solução @FakeRainBrigand, estou sugerindo uma solução mais segura:

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

Então você pode usá-lo assim:

with HiddenPrints():
    print("This will not be printed")

print("This will be printed as before")

Isso é muito mais seguro porque você não pode esquecer de reativar o stdout, o que é especialmente crítico ao lidar com exceções.

# 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.

Se você esqueceu a cláusula finally, nenhuma das suas chamadas print imprimiria mais nada. Usando a instrução with, isso não pode acontecer.

Não é seguro usar sys.stdout = None, porque alguém poderia chamar métodos como sys.stdout.write ()

39
Alexander Chzhen

Não, não há, especialmente que a maioria do PyGame é escrita em C.

Mas se essa função chama print, então é um bug do PyGame, e você deve apenas reportar isso.

4
Cat Plus Plus

Eu tive o mesmo problema, e não cheguei a outra solução, mas para redirecionar a saída do programa (eu não sei exatamente se o spamming acontece em stdout ou stderr) para /dev/null nirvana. 

Na verdade, é de código aberto, mas eu não era apaixonado o suficiente para mergulhar nas fontes pygame - e no processo de compilação - para de alguma forma parar o spam de depuração. 

EDIT:  

O módulo pygame.joystick tem chamadas para printf em todas as funções que retornam os valores reais para o Python:

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

Infelizmente, você precisaria comentá-las e recompilar a coisa toda. Talvez o setup.py fornecido tornasse isso mais fácil do que eu pensava. Você poderia tentar isso ...

2
moooeeeep

Se você deseja bloquear as chamadas de impressão feitas por uma função específica, há uma solução mais simples usando decoradores. Defina o seguinte decorador:

# 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

Em seguida, basta colocar @blockPrinting antes de qualquer função. Por exemplo:

# This will print
def helloWorld():
    print("Hello World!")
helloWorld()

# This will not print
@blockPrinting
def helloWorld2():
    print("Hello World!")
helloWorld2()
1
Fowler

O módulo que usei foi impresso para stderr. Então a solução nesse caso seria:

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

Como sugeriu o @Alexander Chzhen, usar um gerenciador de contexto seria mais seguro do que chamar um par de funções de mudança de estado.

No entanto, você não precisa reimplementar o gerenciador de contexto - ele já está na biblioteca padrão. Você pode redirecionar stdout (o objeto de arquivo que print usa) com contextlib.redirect_stdout e também stderr com contextlib.redirect_stderr.

import os
import contextlib

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

Uma abordagem completamente diferente seria redirecionar na linha de comando. Se você estiver no Windows, isso significa um script em lote. No Linux, bash. 

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

A menos que você esteja lidando com múltiplos processos, este deve funciona. Para usuários do Windows, esses podem ser os atalhos que você está criando (menu iniciar/desktop).

1
FakeRainBrigand