Pergunta

Existe alguma maneira de Python para capturar KeyboardInterrupt evento sem colocar todo o código dentro de um try-except declaração?

Eu quero sair de forma limpa sem rastrear se o usuário pressionar Ctrl+C.

Foi útil?

Solução

Sim, você pode instalar um manipulador de interrupção usando o módulo sinal, e espere para sempre usando um Threading.Event:

import signal
import sys
import time
import threading

def signal_handler(signal, frame):
    print('You pressed Ctrl+C!')
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
forever = threading.Event()
forever.wait()

Outras dicas

Se tudo o que você quiser é não mostrar o Traceback, faça seu código como este:

## all your app logic here
def main():
   ## whatever your app does.


if __name__ == "__main__":
   try:
      main()
   except KeyboardInterrupt:
      # do nothing here
      pass

(Sim, eu sei que isso não responde diretamente à pergunta, mas não está muito claro por que precisar de uma tentativa/exceto o bloco é censurável - talvez isso o torne menos irritante para o OP)

Uma alternativa para definir seu próprio manipulador de sinal é usar um gerente de contexto para pegar a exceção e ignorá-lo:

>>> class CleanExit(object):
...     def __enter__(self):
...             return self
...     def __exit__(self, exc_type, exc_value, exc_tb):
...             if exc_type is KeyboardInterrupt:
...                     return True
...             return exc_type is None
... 
>>> with CleanExit():
...     input()    #just to test it
... 
>>>

Isso remove o try-except Bloqueie ao preservar alguma menção explícita do que está acontecendo.

Isso também permite que você ignore a interrupção apenas em algumas partes do seu código sem precisar definir e redefinir novamente os manipuladores de sinal sempre.

Eu sei que essa é uma pergunta antiga, mas eu vim aqui primeiro e depois descobri o atexit módulo. Eu não sei sobre seu histórico de plataforma cruzada ou uma lista completa de advertências ainda, mas até agora é exatamente o que eu estava procurando ao tentar lidar comKeyboardInterrupt Limpeza no Linux. Só queria jogar outra maneira de abordar o problema.

Eu quero fazer a limpeza pós-exposição no contexto das operações de tecido, então envolver tudo em try/except Também não era uma opção para mim. Sinto-me como atexit Pode ser um bom ajuste nessa situação, onde seu código não está no nível superior do fluxo de controle.

atexit é muito capaz e legível fora da caixa, por exemplo:

import atexit

def goodbye():
    print "You are now leaving the Python sector."

atexit.register(goodbye)

Você também pode usá -lo como decorador (a partir de 2.6; este exemplo é dos documentos):

import atexit

@atexit.register
def goodbye():
    print "You are now leaving the Python sector."

Se você quisesse torná -lo específico KeyboardInterrupt Somente, a resposta de outra pessoa a essa pergunta provavelmente é melhor.

Mas observe que o atexit O módulo tem apenas ~ 70 linhas de código e não seria difícil criar uma versão semelhante que trate exceções de maneira diferente, por exemplo, passando as exceções como argumentos para as funções de retorno de chamada. (A limitação de atexit Isso justificaria uma versão modificada: atualmente não posso conceber uma maneira de as funções de saída de saída de saber sobre as exceções; a atexit O Handler pega a exceção, chama seu (s) retorno (s) de chamada e, em seguida, levanta essa exceção. Mas você pode fazer isso de maneira diferente.)

Para mais informações, consulte:

Você pode evitar imprimir um rastreamento de pilha para KeyboardInterrupt, sem try: ... except KeyboardInterrupt: pass (a solução mais óbvia e propensa a "melhor", mas você já o conhece e pediu outra coisa) substituindo sys.excepthook. Algo como

def custom_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        return # do nothing
    else:
        sys.__excepthook__(type, value, traceback)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top