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やりたいことにはあまり適していません。物事がシャットダウンして終了するため、主に最後の瞬間のリソースのクリーンアップに使用されます。類推すると、それは試行/例外の「最終」ですが、必要なのは試行/例外の「その他」です。

私が考える最も簡単な方法は、スクリプトが「成功」したときにのみ設定するグローバルフラグを作成し続け、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)1つの制限は、成功フラグを設定する前に呼び出すコードがある場合です。このようなコードは、(おそらく)最初にメイン関数に戻るようにリファクタリングする必要があります。これにより、1か所でのみ呼び出すことができ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 に答える