Estou trabalhando em um script python que inicia vários processos e conexões com o banco de dados. De vez em quando eu quero matar o script com um sinal Ctrl+ C, e gostaria de fazer uma limpeza.
No Perl, eu faria o seguinte:
$SIG{'INT'} = 'exit_gracefully';
sub exit_gracefully {
print "Caught ^C \n";
exit (0);
}
Como faço o análogo disso em Python?
./program.py > output.log
,. Quando você pressiona Ctrl-C, deseja que seu programa saia normalmente, registrando que todos os arquivos de dados foram liberados e marcados como limpos para confirmar que estão em bom estado. Mas o Ctrl-C envia o SIGINT a todos os processos em um pipeline, para que o shell possa fechar STDOUT (agora "output.log") antes que o program.py termine de imprimir o log final. O Python irá reclamar, "falha no fechamento do destruidor de objetos de arquivo: Erro no sys.excepthook:".Você pode tratá-lo como uma exceção (KeyboardInterrupt), como qualquer outro. Crie um novo arquivo e execute-o no seu shell com o seguinte conteúdo para ver o que quero dizer:
fonte
signal.signal(signal.SIGINT, signal.default_int_handler)
ou falhará, porque o KeyboardInterrupt não é acionado em todas as situações em que deve ser acionado! Os detalhes estão aqui .E como gerente de contexto:
Usar:
Manipuladores aninhados:
A partir daqui: https://gist.github.com/2907502
fonte
StopIteration
para quebrar o loop mais interno quando um ctrl-C é pressionado, certo?Você pode manipular CTRL+ Ccapturando a
KeyboardInterrupt
exceção. Você pode implementar qualquer código de limpeza no manipulador de exceções.fonte
Da documentação do Python :
fonte
Ainda outro trecho
Referido
main
como a função principal eexit_gracefully
como o manipulador CTRL+cfonte
Eu adaptei o código do @udi para suportar vários sinais (nada extravagante):
Esse código suporta as chamadas de interrupção do teclado (
SIGINT
) eSIGTERM
(kill <process>
)fonte
Em contraste com Matt J, sua resposta, eu uso um objeto simples. Isso me dá a possibilidade de analisar esse manipulador para todos os threads que precisam ser interrompidos na segurança.
Em outro lugar
fonte
time.sleep()
vez de fazer um loop ocupado em uma variável.Você pode usar as funções no módulo de sinal interno do Python para configurar manipuladores de sinal no python. Especificamente, a
signal.signal(signalnum, handler)
função é usada para registrar ahandler
função para sinalsignalnum
.fonte
obrigado pelas respostas existentes, mas adicionei
signal.getsignal()
fonte
Se você quiser garantir que seu processo de limpeza termine, acrescentarei a resposta de Matt J usando um SIG_IGN para que outros itens
SIGINT
sejam ignorados, o que impedirá que sua limpeza seja interrompida.fonte
Pessoalmente, não consegui usar try / except KeyboardInterrupt porque estava usando o modo de soquete padrão (IPC) que está bloqueando. Portanto, o SIGINT foi seguido, mas veio somente após o recebimento de dados no soquete.
Definir um manipulador de sinal se comporta da mesma maneira.
Por outro lado, isso funciona apenas para um terminal real. Outros ambientes de partida pode não aceitar Ctrl+C ou manipular previamente o sinal.
Além disso, existem "Exceções" e "BaseExceptions" no Python, que diferem no sentido de que o intérprete precisa sair de forma limpa, portanto algumas exceções têm uma prioridade mais alta que outras (as exceções são derivadas de BaseException)
fonte