2011-08-22 17 views
6

Quiero ejecutar una tarea cuando finaliza mi programa Python, pero solo si finaliza correctamente. Por lo que yo sé, el uso del módulo atexit significa que mi función registrada será siempre se ejecutará en la terminación del programa, independientemente de su éxito. ¿Existe una funcionalidad similar para registrar una función para que solo se ejecute al salir con éxito? Alternativamente, ¿hay alguna manera para que mi función de salida detecte si la salida fue normal o excepcional?¿Cómo puedo registrar una función para que solo se llame a la salida * successful * de mi programa Python?

Aquí hay algunos códigos que demuestran el problema. Imprimirá que el programa tuvo éxito, incluso cuando falló.

import atexit 

def myexitfunc(): 
    print "Program succeeded!" 

atexit.register(myexitfunc) 

raise Exception("Program failed!") 

Salida:

$ python atexittest.py 
Traceback (most recent call last): 
    File "atexittest.py", line 8, in <module> 
    raise Exception("Program failed!") 
Exception: Program failed! 
Program succeeded! 

Respuesta

4

Fuera de la caja, atexit no es del todo adecuado para lo que quieres hacer: se utiliza principalmente para la limpieza del recurso en el último momento, ya que las cosas están cerrando y saliendo. Por analogía, es el "finalmente" de un try/except, mientras que lo que quieres es el "else" de un try/except.

La manera más simple que puedo pensar es continuar creando una bandera global que establezca solo cuando su secuencia de comandos "tenga éxito" ... y luego tenga todas las funciones conectadas a atexit, marque esa bandera y no haga nada a menos que sea sido establecido.

Ej:

_success = False 
def atsuccess(func, *args, **kwds): 
    def wrapper(): 
     if _success: 
      func(*args,**kwds) 
    atexit(wrapper) 

def set_success(): 
    global _success 
    _success = True 

# then call atsuccess() to attach your callbacks, 
# and call set_success() before your script returns 

Una limitación es que si tienes cualquier código que llama a sys.exit(0) antes de establecer el indicador de éxito. Tal código debería (probablemente) ser refactorizado para regresar primero a la función principal, de modo que llame a set_success y sys.exit en un solo lugar. De no ser así, tendrá que añadir algo como lo siguiente envoltorio alrededor del punto de entrada principal en el script:

try: 
    main() 
except SystemExit, err: 
    if err.code == 0: 
     set_success() 
    raise 
+0

Esta es probablemente la forma más directa de obtener lo que solicité. –

4

envolver el cuerpo de su programa en un comunicado with y definir un objeto de contexto correspondiente que sólo lleva a cabo su acción cuando no se han levantado excepciones. Algo como:

class AtExit(object): 
    def __enter__(self): 
     return self 

    def __exit__(self, exc_type, exc_value, traceback): 
     if exc_value is None: 
      print "Success!" 
     else: 
      print "Failure!" 

if __name__ == "__main__": 
     with AtExit(): 
      print "Running" 
#   raise Exception("Error") 
+0

Esta es una buena forma general de hacer las cosas al salir de una parte del programa, no solo al final de todo el programa. Es un patrón útil, entonces +1. –

Cuestiones relacionadas