8

我想在我的 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!
4

2 回答 2

5

开箱即用,atexit不太适合您想要做的事情:它主要用于在最后一刻进行资源清理,因为事情正在关闭和退出。以此类推,它是 try/except 的“finally”,而您想要的是 try/except 的“else”。

我能想到的最简单的方法是继续创建一个全局标志,只有当你的脚本“成功”时才设置它......然后让你附加的所有功能来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
于 2011-08-22T15:16:07.690 回答
4

将您的程序主体包装在一个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")
于 2011-08-22T15:56:36.507 回答