Neste tutorial, vou ensinar duas formas de disparar uma função quando o script for encerrado. Ele será executado quando o script chegar ao seu final natural ou quando a execução dele for interrompida por um erro.
O objetivo deste tutorial é executar a função abaixo sempre que o script terminar:
def run_on_exit(): print("\r\nHe's dead, Jim!")
Obviamente, você vai criar uma utilidade melhor que apenas dar print em uma linha, mas ela vai servir de exemplo.
A primeira forma de se fazer isso e a que funciona em caso de erros de execução (exceptions) é utilizando o try/catch:
try: print("Hey there! Starting!") inp = input("Input EX to raise an error or just cancel this script (CTRL+C should work)...") if inp.lower().strip() == "ex": raise Exception except Exception: print("This used to work... EXCEPT this instance... ;-)") finally: run_on_exit()
No exemplo acima, se você utilizar o atalho para cancelar a execução (CTRL+C), ele vai ‘pular o fonte’ e executar o que está dentro do finally. Caso você utilize ‘ex‘ como input, ele vai disparar (raise) uma exception e isso vai executar o que está no except primeiro e depois o que está no finally.
Abaixo é o log da execução deste arquivo, apenas apertando ENTER quando ele pedir um input:
Hey there! Starting! Input EX to raise an error or just cancel this script (CTRL+C should work)... He's dead, Jim!
Agora utilizando CTRL+C para interromper:
Hey there! Starting! Input EX to raise an error or just cancel this script (CTRL+C should work)...^C He's dead, Jim! Traceback (most recent call last): File "/home/ubuntu/workspace/exit-script/UsingTryCath.py", line 24, in <module> inp = input("Input EX to raise an error or just cancel this script (CTRL+C should work)...") KeyboardInterrupt
Perceba que, logo após o comando (^C), a função foi executada e a frase “He’s dead, Jim!” foi exibida na tela.
O último deste script é utilizando ex como input:
Hey there! Starting! Input EX to raise an error or just cancel this script (CTRL+C should work)...ex This used to work... EXCEPT this instance... ;-) He's dead, Jim!
Qual a vantagem desta abordagem? Ela é bem flexível e permite maior controle sobre o fluxo do script. Todavia, se o usuário fechar o terminal onde o script está rodando, ele não vai executar a função run_on_exit (que criamos no inicio deste tutorial).
Para resolver este ponto, podemos utilizar o módulo atexit. Primeiro, precisamos importá-lo:
import atexit
O próximo passo é registrar qual função será chamada quando o script estiver fechando:
atexit.register(run_on_exit)
Antigamente, este comando funcionava com qualquer sinal (signal), ou seja, com SIGTERM, SIGINT, SIGQUIT ou SIGABRT. Atualmente, ele só vai ser executado se o sinal for SIGTERM ou se for a finalização normal do script. Esta mudança foi feita, pois utilizar todos os sinais não era (exatamente) uma boa ideia.
Estes sinais (signal) são parte de um módulo específico, chamado signal e sinalizam determinados eventos durante a execução. Para utiliza-los, você precisa importar o módulo.
Exemplo:
import signal
atexit.register(run_on_exit, signal.SIGTERM)
Resumindo: Antigamente (até Python 2.4 +-), você conseguia executar scripts quando o usuário fechava o terminal, mas agora (infelizmente) isso não é mais possível.
Voltando ao tópico deste tutorial, podemos utilizar o script abaixo para testar o atexit:
atexit.register(run_on_exit) print("Hey there! Starting!") inp = input("Don't input anything. Just cancel this script (CTRL+C should work)...")
Executando ele e apertando ENTER na hora do input:
Hey there! Starting! Don't input anything. Just cancel this script (CTRL+C should work)... He's dead, Jim!
A outra forma seria utilizando CTRL+C para interromper:
Hey there! Starting! Don't input anything. Just cancel this script (CTRL+C should work)...^CTraceback (most recent call last): File "/home/ubuntu/workspace/exit-script/UsingAtExit.py", line 28, in <module> inp = input("Don't input anything. Just cancel this script (CTRL+C should work)...") KeyboardInterrupt He's dead, Jim!
Percebe-se uma diferença na utilização destas duas abordagens, mas ambas funcionam. Inclusive, para conseguirmos maior flexibilidade, podemos misturar as duas abordagens.
Se quiser o fonte, ele está no nosso GitHub.
Espero ter ajudado.
Latest posts by Breno RdV (see all)
- O que é Metaclass e como ela funciona. (#python #dev #metaclass) - janeiro 11, 2023
- Entenda a mágica dos Generators. (#python, #dev, #generator, #iterator) - dezembro 28, 2022
- Ordenando um DataFrame por múltiplas colunas. (#python #pandas #jupyter #dev #data) - agosto 3, 2022