エラーと例外の概要

10775 ワード

エラーと例外
これまで誤った情報についてはさらに話したことがありませんが、あなたが実験した例では、いくつか遭遇したことがあるかもしれません.Pythonには、文法エラーと例外(syntax errorsとexceptions)の2つのエラーがあります.
1.構文エラー
文法の間違いは、解析の間違いとも呼ばれ、Pythonを学ぶ過程で最もよく見られる愚痴かもしれません.
>>> while True print('Hello world')
  File "", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

構文解析器は、エラー行を示し、エラーが検出された場所の前に小さな「矢印」を表示します.エラーは矢印の前のタグによって引き起こされる(または少なくともこのように検出される):この例では、関数print()には、前にコロンが1つ欠けているため、エラーが発見される(':').エラーはファイル名と行番号を出力するので、スクリプトから入力した場合は、エラーをチェックする場所がわかります.
2.異常
文または式が文法的に正しい場合でも、実行しようとするとエラーが発生する可能性があります.実行中に検出されたエラーは例外と呼ばれ、プログラムは無条件にクラッシュしません.すぐにPythonプログラムで処理する方法を学びます.しかし、ほとんどの例外はプログラムで処理されず、ここに示すように最終的にエラーメッセージが生成されます.
>>> 10 * (1/0)
Traceback (most recent call last):
  File "", line 1, in ?
ZeroDivisionError: int division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly

エラーメッセージの最後の行は、エラーが発生したことを示します.例外には、エラー情報の一部として例外タイプが表示されます.例の例外は、ゼロ除エラー(ZeroDivisionError)、ネーミングエラー(NameError)、タイプエラー(Type Error)です.エラーメッセージを印刷すると、例外のタイプが例外の内蔵名として表示されます.すべての組み込み例外についてはそうですが、ユーザー定義例外は必ずしもそうではありません(これは役に立つ約束ですが).標準例外名は、内蔵のIDです(キーワードは保持されていません).
この行の後部には、例外タイプに関する詳細な説明があります.これは、その内容が例外タイプに依存していることを意味します.
エラー情報の前半には、例外が発生した場所がスタック形式でリストされます.通常、スタックにソースコード行がリストされますが、標準入力からのソースコードは表示されません.
組み込みの例外には、組み込みの例外とその意味がリストされます.
3.異常処理
プログラミングによって選択された異常を処理することは可能である.次の例を見てください.合法的な整数を入力するまでユーザーに入力を要求しますが、このプログラムを中断することを許可します(Control-Cまたはシステムサポートの任意の方法を使用します).注意:ユーザーによる割り込みにより、KeyboardInterrupt例外が発生します.
>>> while True:
...     try:
...         x = int(input("Please enter a number: "))
...         break
...     except ValueError:
...         print("Oops!  That was no valid number.  Try again...")
...

try文は次のように動作します.
  • まず、try句(tryとexceptキーワードの間の部分)を実行する.
  • 異常が発生しない場合、except句はtry文の実行が完了すると無視されます.
  • try句実行中に異常が発生した場合、その句の残りの部分は無視されます.例外がexceptキーワードの後に指定された例外タイプに一致する場合、対応するexcept句が実行されます.その後try文の実行後のコードを続行します.
  • 異常が発生した場合、except句に一致するブランチがなければ、前のtry文に渡されます.最終的に対応する処理文が見つからない場合は、未処理例外となり、プログラムの実行を終了し、プロンプト情報を表示します.

  • 1つのtry文には、異なる例外の処理を指定する複数のexcept句が含まれる場合があります.せいぜい1つのブランチしか実行されません.例外ハンドラは、対応するtry句で発生する例外のみを処理し、同じtry文で他の句で発生する異常は処理しません.1つのexcept句には、カッコに複数の例外の名前をリストできます.たとえば、次のようにします.
    ... except (RuntimeError, TypeError, NameError):
    ...     pass

    最後のexcept句は、ワイルドカードとして使用するために例外名を省略できます.実際のプログラムエラーを簡単に隠すため、この方法を慎む必要があります.この方法では、エラーメッセージを印刷し、例外を再放出できます(呼び出し元がこの例外を処理できるようにします):
    import sys
    
    try:
        f = open('myfile.txt')
        s = f.readline()
        i = int(s.strip())
    except OSError as err:
        print("OS error: {0}".format(err))
    except ValueError:
        print("Could not convert data to an integer.")
    except:
        print("Unexpected error:", sys.exc_info()[0])
        raise

    try...except文には、すべてのexcept文の後にのみ表示されるelse句を含めることができます.try文に異常が投げ出されていない場合は、この句を使用するためにいくつかのコードを実行する必要があります.例:
    for arg in sys.argv[1:]:
        try:
            f = open(arg, 'r')
        except IOError:
            print('cannot open', arg)
        else:
            print(arg, 'has', len(f.readlines()), 'lines')
            f.close()

    else句を使用すると、try句にコードを追加するよりも、try...exceptが保護されていないコードから放出された異常を予期せぬキャプチャを回避できるため、else句を使用するほうがよい.
    異常が発生した場合、異常のパラメータとして付属値が存在する可能性があります.このパラメータが存在するかどうか、どんなタイプなのかは、異常のタイプに依存します.
    例外名(リスト)の後、except句に変数を指定することもできます.この変数は、instance.argsのパラメータに格納される例外インスタンスにバインドされます.便宜上、例外インスタンスは__を定義します.str__()は、.argsを参照することなく、印刷パラメータに直接アクセスすることができる.このやり方は励まされない.逆に、複数のパラメータを渡す場合はメタグループを渡すことができる異常にパラメータを渡し、messageプロパティにバインドするのがより良い方法です.例外が発生すると、指定したすべてのプロパティが放出される前にバインドされます.
    >>> try:
    ...    raise Exception('spam', 'eggs')
    ... except Exception as inst:
    ...    print(type(inst))    # the exception instance
    ...    print(inst.args)     # arguments stored in .args
    ...    print(inst)          # __str__ allows args to be printed directly,
    ...                         # but may be overridden in exception subclasses
    ...    x, y = inst.args     # unpack args
    ...    print('x =', x)
    ...    print('y =', y)
    ...
    
    ('spam', 'eggs')
    ('spam', 'eggs')
    x = spam
    y = eggs

    未処理の例外については、パラメータが1つある場合、例外情報の最後の部分(「詳細」)として印刷されます.
    例外プロセッサは、try句ですぐに発生する例外だけでなく、try句で呼び出された関数内部で発生する例外も処理します.例:
    >>> def this_fails():
    ...     x = 1/0
    ...
    >>> try:
    ...     this_fails()
    ... except ZeroDivisionError as err:
    ...     print('Handling run-time error:', err)
    ...
    Handling run-time error: int division or modulo by zero

    4.異常放出
    raise文を使用すると、プログラマが指定した例外を強制的に投げ出すことができます.例:
    >>> raise NameError('HiThere')
    Traceback (most recent call last):
      File "", line 1, in ?
    NameError: HiThere

    放出する例外はraiseの一意のパラメータによって識別されます.例外インスタンスまたは例外クラス(Exceptionから継承されたクラス)である必要があります.
    例外が投げ出されるかどうかを明確にする必要があるが、処理したくない場合は、raise文を使用して、例外を簡単に再投げ出すことができます.
    >>> try:
    ...     raise NameError('HiThere')
    ... except NameError:
    ...     print('An exception flew by!')
    ...     raise
    ...
    An exception flew by!
    Traceback (most recent call last):
      File "", line 2, in ?
    NameError: HiThere

    5.ユーザーカスタム例外
    プログラムでは、新しい例外タイプを作成することで、独自の例外の名前を付けることができます(Pythonクラスの内容はクラスを参照).例外クラスは、通常、Exceptionクラスから直接または間接的に派生する必要があります.たとえば、次のようになります.
    >>> class MyError(Exception):
    ...     def __init__(self, value):
    ...         self.value = value
    ...     def __str__(self):
    ...         return repr(self.value)
    ...
    >>> try:
    ...     raise MyError(2*2)
    ... except MyError as e:
    ...     print('My exception occurred, value:', e.value)
    ...
    My exception occurred, value: 4
    >>> raise MyError('oops!')
    Traceback (most recent call last):
      File "", line 1, in ?
    __main__.MyError: 'oops!'

    この例では、Exceptionのデフォルトの_init__()上書きされます.新しい方法でvalueプロパティを簡単に作成します.これにより、argsプロパティを作成する方法が置き換えられます.
    例外クラスでは、他のクラスで定義できるものを定義できますが、通常は簡単に保つために、例外処理ハンドル抽出のためにいくつかの属性情報のみを追加します.新しく作成されたモジュールでいくつかの異なるエラーを投げ出す必要がある場合、通常の方法は、モジュールに例外ベースクラスを定義し、異なるエラータイプに対して対応する例外サブクラスを派生させることです.
    class Error(Exception):
        """Base class for exceptions in this module."""
        pass
    
    class InputError(Error):
        """Exception raised for errors in the input.
    
        Attributes:
            expression -- input expression in which the error occurred
            message -- explanation of the error
        """
    
        def __init__(self, expression, message):
            self.expression = expression
            self.message = message
    
    class TransitionError(Error):
        """Raised when an operation attempts a state transition that's not
        allowed.
    
        Attributes:
            previous -- state at beginning of transition
            next -- attempted new state
            message -- explanation of why the specific transition is not allowed
        """
    
        def __init__(self, previous, next, message):
            self.previous = previous
            self.next = next
            self.message = message

    標準例外と同様に、ほとんどの例外の名前は「Error」で終わります.
    多くの標準モジュールでは、定義した関数で発生する可能性のあるエラーを報告するために、独自の例外が定義されています.クラスの詳細については、クラスの章を参照してください.
    6.クリーンアップ動作の定義
    try文には、任意の場合に実行する機能を定義するためのオプションの句もあります.例:
    >>> try:
    ...     raise KeyboardInterrupt
    ... finally:
    ...     print('Goodbye, world!')
    ...
    Goodbye, world!
    KeyboardInterrupt
    Traceback (most recent call last):
      File "", line 2, in ?

    異常が発生しているかどうかにかかわらず、finally句はプログラムがtryを離れた後に必ず実行されます.try文にexceptによって取得されていない異常(またはexceptまたはelse句で発生)が発生すると、finally文の実行が完了すると再放出されます.try文はbreak,continueまたはreturn文を介して終了してもfinally句が実行されます.以下に、より複雑な例を示します.
    >>> def divide(x, y):
    ...     try:
    ...         result = x / y
    ...     except ZeroDivisionError:
    ...         print("division by zero!")
    ...     else:
    ...         print("result is", result)
    ...     finally:
    ...         print("executing finally clause")
    ...
    >>> divide(2, 1)
    result is 2
    executing finally clause
    >>> divide(2, 0)
    division by zero!
    executing finally clause
    >>> divide("2", "1")
    executing finally clause
    Traceback (most recent call last):
      File "", line 1, in ?
      File "", line 3, in divide
    TypeError: unsupported operand type(s) for /: 'str' and 'str'

    ご覧のように、finally句はどんな場合でも実行されます.TypeErrorは、2つの文字列を除いたときに投げ出され、except句に取り込まれなかったため、finally句の実行が完了した後に再び投げ出される.
    実際のシーンのアプリケーションでは、finally句は、使用中にエラーが発生したかどうかにかかわらず、外部リソース(ファイルまたはネットワーク接続など)を解放するために使用されます.
    8.7. 事前定義されたクリーンアップ動作
    オブジェクトの操作が成功したかどうかにかかわらず、オブジェクトが不要になったときに機能する標準的なクリーンアップ動作を定義するオブジェクトもあります.次の例では、ファイルを開いて画面に印刷してみます.
    for line in open("myfile.txt"):
        print(line)

    このコードの問題は、コードの実行が完了した後、開いているファイルをすぐに閉じていないことです.これは簡単なスクリプトではありませんが、大規模なアプリケーションでは問題が発生します.with文は、ファイルなどのオブジェクトが常に正確にクリーンアップされることを保証します.
    with open("myfile.txt") as f:
        for line in f:
            print(line)

    文が実行されると、ファイルfは常に閉じられ、ファイル内のデータの処理中にエラーが発生しても同様である.他のオブジェクトが定義済みのクリーンアップ動作を提供しているかどうかは、ドキュメントを表示します.