1. ホーム
  2. python

[解決済み] 例外に情報を追加する?

2022-04-15 21:36:48

質問

こんなことを実現したい

def foo():
   try:
       raise IOError('Stuff ')
   except:
       raise

def bar(arg1):
    try:
       foo()
    except Exception as e:
       e.message = e.message + 'happens at %s' % arg1
       raise

bar('arg1')

Traceback...
  IOError('Stuff Happens at arg1')

しかし、私が得たものは

Traceback..
  IOError('Stuff')

これを実現するためのヒントがあれば教えてください。Python 2 と 3 の両方で行うにはどうしたらいいですか?

どのように解決するのですか?

私ならこのようにします。 foo() で変更する必要はありません。 bar() .

def foo():
    try:
        raise IOError('Stuff')
    except:
        raise

def bar(arg1):
    try:
        foo()
    except Exception as e:
        raise type(e)(e.message + ' happens at %s' % arg1)

bar('arg1')


Traceback (most recent call last):
  File "test.py", line 13, in <module>
    bar('arg1')
  File "test.py", line 11, in bar
    raise type(e)(e.message + ' happens at %s' % arg1)
IOError: Stuff happens at arg1

アップデート1

ここでは、元のトレースバックを保持するために若干の修正を加えています。

...
def bar(arg1):
    try:
        foo()
    except Exception as e:
        import sys
        raise type(e), type(e)(e.message +
                               ' happens at %s' % arg1), sys.exc_info()[2]

bar('arg1')


Traceback (most recent call last):
  File "test.py", line 16, in <module>
    bar('arg1')
  File "test.py", line 11, in bar
    foo()
  File "test.py", line 5, in foo
    raise IOError('Stuff')
IOError: Stuff happens at arg1

アップデート2

Python 3.x では、最初のアップデートのコードは構文的に正しくなく、さらに message 属性に BaseException PEP 352の変更で撤回された を2012-05-16に投稿しました(私の最初の更新は2012-03-12)。したがって、現在、とにかく Python 3.5.2 では、トレースバックを保持し、関数内の例外のタイプをハードコードしないために、次のような行を行う必要があります。 bar() . また、行があることに注意してください。

During handling of the above exception, another exception occurred:

が、表示されるトレースバックメッセージに表示されます。

# for Python 3.x
...
def bar(arg1):
    try:
        foo()
    except Exception as e:
        import sys
        raise type(e)(str(e) +
                      ' happens at %s' % arg1).with_traceback(sys.exc_info()[2])

bar('arg1')

アップデート3

コメントで、Python 2 と 3 の両方で動作する方法はないのか、という質問がありました。構文の違いから答えは "No"と思われるかも知れませんが のようなヘルパー関数を使用することで、それを回避することができます。 reraise() の中に six アドオンモジュールです。そこで、何らかの理由でライブラリを使いたくないという方のために、以下は簡略化したスタンドアローン版です。

また、例外の発生は reraise() 関数を呼び出すと、どのようなトレースバックが発生しても、最終的な結果はあなたが望むものになります。

import sys

if sys.version_info.major < 3:  # Python 2?
    # Using exec avoids a SyntaxError in Python 3.
    exec("""def reraise(exc_type, exc_value, exc_traceback=None):
                raise exc_type, exc_value, exc_traceback""")
else:
    def reraise(exc_type, exc_value, exc_traceback=None):
        if exc_value is None:
            exc_value = exc_type()
        if exc_value.__traceback__ is not exc_traceback:
            raise exc_value.with_traceback(exc_traceback)
        raise exc_value

def foo():
    try:
        raise IOError('Stuff')
    except:
        raise

def bar(arg1):
    try:
       foo()
    except Exception as e:
        reraise(type(e), type(e)(str(e) +
                                 ' happens at %s' % arg1), sys.exc_info()[2])

bar('arg1')