[Python: Tutorial] Como executar funções ao fechar o script.

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.

The following two tabs change content below.
Arquiteto de Software e Desenvolvedor Backend (quase Fullstack), geralmente trabalho com C#, PowerShell, Python, Golang, bash e Unity (esse é mais por hobby). Estou sempre buscando algo novo para aprender, adicionando novas ferramentas ao meu cinto de utilidades.
Posted in Dev, Python and tagged , , , , , .