Как я могу зарегистрировать функцию, которая будет вызываться только при * успешном * выходе из моей программы Python? - PullRequest
6 голосов
/ 22 августа 2011

Я хочу выполнить задачу, когда моя программа на Python завершит свою работу, но только если она успешно завершится.Насколько я знаю, использование модуля atexit означает, что моя зарегистрированная функция будет всегда запускаться при завершении программы, независимо от успеха.Существуют ли аналогичные функции для регистрации функции, чтобы она выполнялась только при успешном завершении?В качестве альтернативы, есть ли способ для моей функции выхода определить, был ли выход нормальным или исключительным?

Вот код, демонстрирующий проблему.Будет напечатано, что программа выполнена успешно, даже если она не удалась.

import atexit

def myexitfunc():
    print "Program succeeded!"

atexit.register(myexitfunc)

raise Exception("Program failed!")

Вывод:

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

Ответы [ 2 ]

4 голосов
/ 22 августа 2011

Оберните тело вашей программы в оператор with и определите соответствующий объект контекста, который выполняет ваше действие, только когда не возникло никаких исключений. Что-то вроде:

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")
4 голосов
/ 22 августа 2011

Из коробки atexit не совсем подходит для того, что вы хотите сделать: он в основном используется для очистки ресурсов в самый последний момент, когда все закрывается и завершается.По аналогии, это «finally» попытки / исключения, тогда как вы хотите «еще» попытки / исключения.

Самый простой способ, о котором я могу подумать, - это продолжать создавать глобальный флаг, который вы устанавливаете только тогда, когда ваш скрипт «завершается успешно» ... и затем все функции, которые вы прикрепляете к atexit, проверяют этот флаг,ничего не делать, если он не установлен.

Например:

_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

Одно ограничение - если у вас есть какой-либо код, который вызывает sys.exit(0) перед установкой флага успеха.Такой код (вероятно) следует реорганизовать, чтобы сначала вернуться к основной функции, чтобы вы вызывали set_success и sys.exit только в одном месте.В противном случае вам нужно добавить что-то вроде следующей оболочки вокруг главной точки входа в вашем скрипте:

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