Fazer algo antes de sair do programa

100

Como você pode ter uma função ou algo que será executado antes de seu programa encerrar? Eu tenho um script que será executado constantemente em segundo plano e preciso salvar alguns dados em um arquivo antes de sair. Existe uma maneira padrão de fazer isso?

RacecaR
fonte
2
O script nunca deve parar, mas talvez alguém interrompa o processo ou pressione Ctrl + \ ou algo assim.
RacecaR

Respostas:

165

Confira o atexitmódulo:

http://docs.python.org/library/atexit.html

Por exemplo, se eu quisesse imprimir uma mensagem quando meu aplicativo estava sendo encerrado:

import atexit

def exit_handler():
    print 'My application is ending!'

atexit.register(exit_handler)

Esteja ciente de que isso funciona muito bem para o encerramento normal do script, mas não será chamado em todos os casos (por exemplo, erros internos fatais).

Brent escreve código
fonte
5
Existe alguma maneira de torná-lo onde será chamado se você pressionar Ctrl + C ou Ctrl + \?
RacecaR
8
Ele será chamado se você pressionar Ctrl + C. Isso simplesmente gera uma exceção KeyboardInterrupt.
Ned Batchelder,
1
Oh, eu esqueci disso. E suponho que nada do que você possa fazer será executado se alguém interromper o processo do python, certo?
RacecaR
5
@RacecaR: de fato; o objetivo de matar um processo é interrompê-lo. De docs: Note The exit function is not called when the program is killed by a signal, when a Python fatal internal error is detected, or when os._exit() is called.
Katriel,
18
@RacecaR, a única maneira de executar o código de terminação mesmo se um processo travar gravemente ou for brutalmente eliminado é em outro processo, conhecido como "monitor" ou "watchdog", cuja única função é ficar de olho no processo de destino e execute o código de terminação quando apropriado. É claro que isso requer uma arquitetura muito diferente e tem suas limitações; se precisar dessa funcionalidade, é melhor abrir um outro Q sobre o assunto.
Alex Martelli,
32

Se você quer que algo sempre rode, mesmo com erros, use try: finally:assim -

def main():
    try:
        execute_app()
    finally:
        handle_cleanup()

if __name__=='__main__':
    main()

Se você também quiser lidar com exceções, pode inserir um except:antes definally:

Brian C. Lane
fonte
13
Não funciona quando o SIGTERM ocorre devido à eliminação do processo.
ramu
16

Se você parar o script levantando um KeyboardInterrupt(por exemplo, pressionando Ctrl-C), você pode pegar isso apenas como uma exceção padrão. Você também pode pegar SystemExitda mesma maneira.

try:
    ...
except KeyboardInterrupt:
    # clean up
    raise

Menciono isso apenas para que você saiba; a maneira 'certa' de fazer isso é o atexitmódulo mencionado acima.

Katriel
fonte