15

excepttlndr: 関数がブロックから (直接/間接的に)呼び出されたかどうかを関数で伝える方法。python2.7/cpython.

__context__私はpython 2.7を使用し、カスタム例外クラスにpy3に似たものを提供しようとしています:

class MyErr(Exception):
    def __init__(self, *args):
        Exception.__init__(self, *args)
        self.context = sys.exc_info()[1]
    def __str__(self):
        return repr(self.args) + ' from ' + repr(self.context)

これはうまくいくようです:

try:
   1/0
except:
   raise MyErr('bang!')

#>__main__.MyErr: ('bang!',) from ZeroDivisionError('integer division or modulo by zero',)

MyErr例外ブロックの外で発生させる必要がある場合があります。これもいいです:

raise MyErr('just so')

#>__main__.MyErr: ('just so',) from None

ただし、この時点より前に処理された例外があった場合は、次のコンテキストとして誤って設定されていますMyErr

try:
    print xxx
except Exception as e:
    pass

# ...1000 lines of code....
raise MyErr('look out')

#>__main__.MyErr: ('look out',) from NameError("name 'xxx' is not defined",) <-- BAD

sys.exc_infoその理由は、単に「現在の」例外ではなく「最後」の例外を返すことだと思い ます。

この関数は、現在処理されている例外に関する情報を提供する 3 つの値のタプルを返します。<...> ここで、「例外を処理する」とは、「 except 句を実行する、または実行したこと」と定義します。

したがって、私の質問は、インタプリタがexcept句を実行しているかどうか(過去に実行されていないかどうか)を確認する方法です。言い換えれば、スタックにアップMyErr.__init__があるかどうかを知る方法はありますか?except

私のアプリは移植性がありません。Cpython 固有のハックは大歓迎です。

4

4 に答える 4

1

sys.exc_clear()1 つの解決策は、例外が処理された後に呼び出すことです。

import sys

class MyErr(Exception):
    def __init__(self, *args):
        Exception.__init__(self, *args)
        self.context = sys.exc_info()[1]
    def __str__(self):
        return repr(self.args) + ' from ' + repr(self.context)

try:
    print xxx
except Exception as e:
    # exception handled
    sys.exc_clear()

raise MyErr('look out')

与えます:

Traceback (most recent call last):
  File "test.py", line 18, in <module>
    raise MyErr('look out')`
__main__.MyErr: ('look out',) from None

発生させずに例外を処理する場所があまりない場合は、コンストラクター引数を提供MyErrするように呼び出しを変更したり、この回答のようにトレースバックの保存を明示的に処理したりするよりも適している可能性があります。MyErr

于 2013-10-09T21:47:32.887 に答える