Hacer algo antes de salir del programa

100

¿Cómo puede tener una función o algo que se ejecutará antes de que se cierre el programa? Tengo un script que se ejecutará constantemente en segundo plano y lo necesito para guardar algunos datos en un archivo antes de que salga. ¿Existe una forma estándar de hacer esto?

Coche de carreras
fuente
2
La secuencia de comandos nunca debería detenerse, pero tal vez alguien mate el proceso o presione Ctrl + \ o algo.
RacecaR

Respuestas:

165

Mira el atexitmódulo:

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

Por ejemplo, si quisiera imprimir un mensaje cuando mi aplicación estaba terminando:

import atexit

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

atexit.register(exit_handler)

Solo tenga en cuenta que esto funciona muy bien para la terminación normal del script, pero no se llamará en todos los casos (por ejemplo, errores internos fatales).

Brent escribe código
fuente
5
¿Hay alguna forma de hacerlo donde se llamará si presiona Ctrl + C o Ctrl + \?
RacecaR
8
Se llamará si presiona Ctrl + C. Eso simplemente genera una excepción KeyboardInterrupt.
Ned Batchelder
1
Oh, lo olvidé. Y supongo que nada de lo que pueda hacer se ejecutará si alguien mata el proceso de Python, ¿verdad?
RacecaR
5
@RacecaR: de hecho; el objetivo de matar un proceso es detenerlo. A partir de los documentos: 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, la única forma en que puede ejecutar el código de terminación incluso si un proceso falla o es brutalmente asesinado es en otro proceso, conocido como "monitor" o "perro guardián", cuyo único trabajo es vigilar el proceso objetivo y ejecute el código de terminación cuando sea apropiado. Por supuesto que requiere una arquitectura muy diferente y tiene sus limitaciones; si necesita dicha funcionalidad, es mejor que abra una Q diferente al respecto.
Alex Martelli
32

Si desea que algo se ejecute siempre, incluso con errores, use try: finally:así:

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

if __name__=='__main__':
    main()

Si también desea manejar excepciones, puede insertar un except:antes delfinally:

Brian C. Lane
fuente
13
No funciona cuando se produce SIGTERM debido a la eliminación del proceso.
ramu
16

Si detiene el script levantando un KeyboardInterrupt(por ejemplo, presionando Ctrl-C), puede detectarlo como una excepción estándar. También puedes pescar SystemExitde la misma forma.

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

Menciono esto solo para que lo sepas; la forma "correcta" de hacer esto es el atexitmódulo mencionado anteriormente.

Katriel
fuente