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

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

Overview

Olá, entusiastas do Python! Hoje, vamos mergulhar em um tutorial prático sobre como assegurar que uma função específica seja executada ao finalizar seus scripts, independentemente de serem concluídos naturalmente ou interrompidos por um erro. Vamos explorar duas abordagens valiosas: a clássica estrutura try/catch e o módulo atexit. Essas técnicas simples, mas poderosas, vão adicionar uma camada extra de robustez e flexibilidade aos seus projetos. Preparados? Vamos lá!

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.