Respostas:
Sim, você pode instalar um manipulador de interrupção usando o sinal do módulo e esperar para sempre usando um threading . Evento :
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()
while True: continue
. (Nesse estilo, while True: pass
seria mais puro, de qualquer maneira.) Isso seria um grande desperdício; tente algo como while True: time.sleep(60 * 60 * 24)
(dormir um dia de cada vez é uma figura inteiramente arbitrária).
time
(como deveria), não se esqueça de import time
:)
Se tudo o que você quer é não mostrar o traceback, faça seu código assim:
## 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 a necessidade de um bloco try / except é questionável - talvez isso o torne menos incômodo para o OP)
signal.signal( signal.SIGINT, lambda s, f : sys.exit(0))
sempre faz.
Uma alternativa para definir seu próprio manipulador de sinal é usar um gerenciador de contexto para capturar a exceção e ignorá-la:
>>> 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 bloco try
- except
enquanto preserva 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 ter que definir e redefinir novamente os manipuladores de sinal todas as vezes.
Eu sei que esta é uma pergunta antiga, mas eu vim aqui primeiro e depois descobri o atexit
módulo. 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 com o pós- KeyboardInterrupt
limpeza no Linux. Só queria apresentar outra maneira de abordar o problema.
Quero fazer uma limpeza pós-saída no contexto das operações do Fabric, portanto, encerrar tudo try
/ except
não era uma opção para mim também. Acho que atexit
pode ser um bom ajuste em tal 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 um 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ê quiser torná-lo específico KeyboardInterrupt
apenas para , a resposta de outra pessoa a essa pergunta provavelmente é melhor.
Mas observe que o atexit
módulo tem apenas ~ 70 linhas de código e não seria difícil criar uma versão semelhante que trate as exceções de maneira diferente, por exemplo, passando as exceções como argumentos para as funções de retorno de chamada. (A limitação atexit
disso garantiria uma versão modificada: atualmente, não consigo conceber uma maneira de as funções de retorno de chamada de saída saberem sobre as exceções; o atexit
manipulador captura a exceção, chama seu (s) retorno (ões) de chamada e aumenta novamente essa exceção. Mas você poderia fazer isso de forma diferente.)
Para obter mais informações, consulte:
atexit
Você pode evitar a impressão de um rastreamento de pilha para KeyboardInterrupt
, sem try: ... except KeyboardInterrupt: pass
(a solução mais óbvia e provavelmente a "melhor", mas você já a 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)
Tentei as soluções sugeridas por todos, mas tive que improvisar o código sozinho para fazê-lo funcionar. A seguir está meu código improvisado:
import signal
import sys
import time
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
print(signal) # Value is 2 for CTRL + C
print(frame) # Where your execution of program is at moment - the Line Number
sys.exit(0)
#Assign Handler Function
signal.signal(signal.SIGINT, signal_handler)
# Simple Time Loop of 5 Seconds
secondsCount = 5
print('Press Ctrl+C in next '+str(secondsCount))
timeLoopRun = True
while timeLoopRun:
time.sleep(1)
if secondsCount < 1:
timeLoopRun = False
print('Closing in '+ str(secondsCount)+ ' seconds')
secondsCount = secondsCount - 1