web-dev-qa-db-ja.com

Pythonで手動で例外を発生させる(スローする)

Pythonで例外を発生させ、後でexceptブロックを介して捕捉できるようにするにはどうすればよいですか。

1866
TIMEX

Pythonで例外を手動でスロー/発生させるにはどうすればよいですか?

問題に意味的に適合する最も具体的な例外コンストラクターを使用

メッセージに具体的に記入してください、例:

raise ValueError('A very specific bad thing happened.')

一般的な例外を発生させない

一般的な例外を発生させないでください。それをキャッチするには、それをサブクラス化する他のすべてのより具体的な例外をキャッチする必要があります。

問題1:バグを隠す

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

例えば:

def demo_bad_catch():
    try:
        raise ValueError('Represents a hidden bug, do not catch this')
        raise Exception('This is the exception you expect to handle')
    except Exception as error:
        print('Caught this error: ' + repr(error))

>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)

問題2:キャッチされない

より具体的なキャッチは一般的な例外をキャッチしません:

def demo_no_catch():
    try:
        raise Exception('general exceptions not caught by specific handling')
    except ValueError as e:
        print('we will not catch exception: Exception')


>>> demo_no_catch()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling

ベストプラクティス:raiseステートメント

代わりに、問題に意味的に適合する最も具体的な例外コンストラクターを使用します

raise ValueError('A very specific bad thing happened')

また、コンストラクタに任意の数の引数を渡すこともできます:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

これらの引数は、Exceptionオブジェクトのargs属性によってアクセスされます。例えば:

try:
    some_code_that_may_raise_our_value_error()
except ValueError as err:
    print(err.args)

プリント

('message', 'foo', 'bar', 'baz')    

Python 2.5では、例外をサブクラス化し、messageの使用を停止することをユーザーに推奨するために、実際のargs属性がBaseExceptionに追加されましたが、 messageおよびargsの元の廃止は撤回されました

ベストプラクティス:except

Except節内では、たとえば、特定のタイプのエラーが発生したことをログに記録してから、再度発生させることができます。スタックトレースを保持しながらこれを行う最良の方法は、bare raiseステートメントを使用することです。例えば:

logger = logging.getLogger(__name__)

try:
    do_something_in_app_that_breaks_easily()
except AppError as error:
    logger.error(error)
    raise                 # just this!
    # raise AppError      # Don't do this, you'll lose the stack trace!

エラーを修正しないでください...しかし、あなたが主張する場合。

sys.exc_info()を使用してスタックトレース(およびエラー値)を保存できますが、これはエラーが発生しやすいおよびPython 2と3の間に互換性の問題があります。再レイズするには、裸のraiseを使用することをお勧めします。

説明するには-sys.exc_info()はタイプ、値、およびトレースバックを返します。

type, value, traceback = sys.exc_info()

これはPython 2の構文です-これはPython 3と互換性がないことに注意してください:

    raise AppError, error, sys.exc_info()[2] # avoid this.
    # Equivalently, as error *is* the second object:
    raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

必要に応じて、新しいレイズで何が起こるかを変更できます。インスタンスに新しい引数を設定する:

def error():
    raise ValueError('oops!')

def catch_error_modify_message():
    try:
        error()
    except ValueError:
        error_type, error_instance, traceback = sys.exc_info()
        error_instance.args = (error_instance.args[0] + ' <modification>',)
        raise error_type, error_instance, traceback

そして、引数を変更する間、トレースバック全体を保存しました。これはベストプラクティスではなくであり、それは無効な構文であることに注意してくださいPython 3(互換性の維持を回避するのがはるかに難しくなります)。

>>> catch_error_modify_message()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in catch_error_modify_message
  File "<stdin>", line 2, in error
ValueError: oops! <modification>

Python

    raise error.with_traceback(sys.exc_info()[2])

繰り返しますが、手動でトレースバックを操作することは避けてください。 非効率的 であり、エラーが発生しやすくなります。スレッドとsys.exc_infoを使用している場合、間違ったトレースバックを取得することさえあります(特に、制御フローに例外処理を使用している場合-私は個人的には避けがちです)。

Python 3、例外チェーン

Python 3では、トレースバックを保持する例外をチェーンできます。

    raise RuntimeError('specific message') from error

注意してください:

  • このdoesは、発生したエラータイプの変更を許可します。
  • これは、Python 2と互換性のあるnotです。

非推奨のメソッド:

これらは容易に隠され、実動コードにさえ入り込む可能性があります。例外を発生させたい場合、それらを実行すると例外が発生しますが、意図したものではありません!

Python 2では有効ですが、Python 3では無効 は次のとおりです。

raise ValueError, 'message' # Don't do this, it's deprecated!

Pythonの非常に古いバージョンで有効 (2.4以前)のみ、文字列を上げる人がまだいることがあります。

raise 'message' # really really wrong. don't do this.

すべての最新バージョンでは、BaseException型を発生させていないため、これは実際にTypeErrorを発生させます。適切な例外をチェックしておらず、問題を認識しているレビュアーがいない場合、プロダクションに入る可能性があります。

使用例

APIを誤って使用している場合、APIの消費者に警告する例外を発生させます。

def api_func(foo):
    '''foo should be either 'baz' or 'bar'. returns something very useful.'''
    if foo not in _ALLOWED_ARGS:
        raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))

適切なときに独自のエラータイプを作成する

"意図的にエラーを出したいので、例外になります"

独自のエラータイプを作成できます。アプリケーションに特定の何かが間違っていることを示したい場合は、例外階層の適切なポイントをサブクラス化するだけです。

class MyAppLookupError(LookupError):
    '''raise this when there's a lookup error for my app'''

および使用法:

if important_key not in resource_dict and not ok_to_be_missing:
    raise MyAppLookupError('resource is missing, and that is not ok.')
2537
Aaron Hall

これをしないでください 。裸のExceptionを上げることは絶対に ではありません 正しいことです。 Aaron Hallのすばらしい答えを参照してください 代わりに。

これ以上のPythonicを手に入れることはできません。

raise Exception("I know python!")

詳細については、 raise文のdocs pythonを参照してください。

528
Gabriel Hurley

予期しない状況に対応して例外をスローする必要があり、決してキャッチするつもりはないのですが、発生した場合にそこからデバッグできるようにするために単に速く失敗するという最も一般的なケース - AssertionError

if 0 < distance <= RADIUS:
    #Do something.
Elif RADIUS < distance:
    #Do something.
else:
    raise AssertionError("Unexpected value of 'distance'!", distance)
32
Evgeni Sergeev

Python 3では、例外を発生させるための4つの異なる構文があります。

1. raise exception 
2. raise exception (args) 
3. raise
4. raise exception (args) from original_exception

1.例外を発生させる対2.例外を発生させる(引数)

raise exception (args)を使用して例外を発生させると、以下の例に示すように、例外オブジェクトを印刷するときにargsが印刷されます。

  #raise exception (args)
    try:
        raise ValueError("I have raised an Exception")
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error I have raised an Exception 



  #raise execption 
    try:
        raise ValueError
    except ValueError as exp:
        print ("Error", exp)     # Output -> Error 

3.レイズ

引数を指定しないraiseステートメントは、最後の例外を発生させます。これは、例外をキャッチした後に何らかのアクションを実行する必要があり、その後それを再度発生させたい場合に役立ちます。しかし、以前に例外がなかった場合、raiseステートメントはTypeError Exceptionを発生させます。

def somefunction():
    print("some cleaning")

a=10
b=0 
result=None

try:
    result=a/b
    print(result)

except Exception:            #Output ->
    somefunction()           #some cleaning
    raise                    #Traceback (most recent call last):
                             #File "python", line 8, in <module>
                             #ZeroDivisionError: division by zero

4. original_exceptionから例外(args)を発生させる

次の例に示すように、このステートメントは、別の例外に応答して発生した例外に元の例外の詳細を含めることができる例外チェーンを作成するために使用されます。

class MyCustomException(Exception):
pass

a=10
b=0 
reuslt=None
try:
    try:
        result=a/b

    except ZeroDivisionError as exp:
        print("ZeroDivisionError -- ",exp)
        raise MyCustomException("Zero Division ") from exp

except MyCustomException as exp:
        print("MyException",exp)
        print(exp.__cause__)

出力:

ZeroDivisionError --  division by zero
MyException Zero Division 
division by zero
30
N Randhawa

既存の回答を先に読んでください。これは単なる補足です。

引数があってもなくても例外を発生させることができることに注意してください。

例:

raise SystemExit

プログラムを終了しますが、何が起こったのか知りたいと思うかもしれません。あなたはこれを使うことができます。

raise SystemExit("program exited")

これはプログラムを閉じる前に "program exited"をstderrに出力します。

10
Anant Prakash

例外をスローするもう1つの方法は assert です。もしそうでなければAssertionErrorを発生させるであろうならば、あなたは条件が満たされていることを検証するためにassertを使うことができます。詳細は こちら をご覧ください。

def avg(marks):
    assert len(marks) != 0,"List is empty."
    return sum(marks)/len(marks)

mark2 = [55,88,78,90,79]
print("Average of mark2:",avg(mark2))

mark1 = []
print("Average of mark1:",avg(mark1))
0
Rehan Haider

注意してください:一般的な例外を処理したいことがあります。大量のファイルを処理してエラーを記録している場合は、ファイルに発生したエラーを検出して記録し、残りのファイルの処理を続けることをお勧めします。その場合、try except Exception:ブロックはそれを実行するための良い方法です。あなたはまだraise特定の例外をしたいと思うでしょう。

0
markemus