Python3 のエラーと例外


Python の初心者として、初めて Python プログラミングを学習すると、これまで言及しなかったいくつかのエラー メッセージがよく表示されますが、この章では具体的に説明します。

Python には、構文エラーと例外という、簡単に識別できる 2 種類のエラーがあります。

構文エラー

Python の構文エラー、または解析エラーは、初心者がよく遭遇します。次の例では、関数 print() の前に関数が欠落しているため、エラーが見つかりました。それのコロン(:)。

パーサーはエラーのある行を指摘し、最初に見つかったエラーを小さな矢印でマークします。

例外

Python プログラムの構文が正しい場合でも、実行時にエラーが発生する場合があります。実行時に検出されるエラーは例外と呼ばれます。

ほとんどの例外はプログラムによって処理されず、エラー メッセージの形式でここに表示されます:

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

例外はさまざまなタイプで表示され、これらのタイプは情報の一部として出力されます: この例のタイプには以下が含まれます: ZeroDivisionError、NameError、TypeError。

エラー メッセージの先頭部分には、例外が発生したコンテキストが示され、コール スタックの形式で特定の情報が表示されます。

例外処理

次の例では、ユーザーは正当な整数を入力できますが、プログラムを中断することもできます (Control-C またはオペレーティング システムが提供するメソッドを使用)。ユーザーがメッセージを中断すると、KeyboardInterrupt 例外が発生します。

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly

try ステートメントは次のように動作します。

    まず、try 節 (キーワード try とキーワード else の間のステートメント) が実行されます。
  • 例外が発生しない場合、excel 節は無視され、 try 句 文が実行された後に終了します。
  • try 句の実行中に例外が発生した場合、try 句の残りの部分は無視されます。例外の種類が、Except の後の名前と一致する場合、対応するExcept 句が実行されます。最後に、try ステートメントの後のコードを実行します。
  • 例外がどの例外とも一致しない場合、この例外は上位の try に渡されます。
  • try ステートメントには、さまざまな特定の例外を処理するために複数の else 句が含まれる場合があります。最大 1 つのブランチが実行されます。

ハンドラーは、対応する try 句の例外のみを処理し、他の try ハンドラーの例外は処理しません。

Except 句は同時に複数の例外を処理できます。これらの例外は括弧内に置かれてタプルを形成します。例:

>>> while True:
        try:
            x = int(input("Please enter a number: "))
            break
        except ValueError:
            print("Oops!  That was no valid number.  Try again   ")

最後の例外句は例外の名前を無視でき、例外として使用されます。ワイルドカード。このメソッドを使用すると、エラー メッセージを出力し、再度例外をスローできます。

    except (RuntimeError, TypeError, NameError):
        pass

try 例外ステートメントにはオプションの else 句もあります。この句を使用する場合は、すべての else 句の後に配置する必要があります。この句は、try 句で例外が発生しなかった場合に実行されます。例:

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

else 句を使用することは、Except によってキャッチされない予期しない例外を避けるために、すべてのステートメントを Try 句に入れるよりも優れています。

例外処理は、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()

例外をスローする

Python は、raise ステートメントを使用して、指定された例外をスローします。例:

>>> 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

raise 唯一のパラメータは、スローされる例外を指定します。これは、例外インスタンスまたは例外クラス (つまり、Exception のサブクラス) である必要があります。

これが例外をスローしたかどうかを知りたいだけで、それを処理したくない場合は、単純な raise ステートメントで例外を再度発生させることができます。

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

ユーザー定義の例外

新しい例外クラスを作成することで、独自の例外を設定できます。例外は、直接的または間接的に、Exception クラスから継承する必要があります。例:

>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
   
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

この例では、クラス Exception のデフォルトの __init__() がオーバーライドされます。

<pException クラスは他のクラスと同様に何でも実行できますが、通常はより単純で、いくつかのエラー関連プロパティのみを提供し、例外を処理するコードがこの情報を簡単に取得できるようにします。 < p="">

さまざまな例外をスローする可能性のあるモジュールを作成する場合、一般的なアプローチは、パッケージの基本例外クラスを作成し、この基本クラスに基づいてさまざまなエラー状況に対応する新しいクラスを作成することです。サブクラス:

>>> 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 "<stdin>", line 1, in ?
__main__.MyError: 'oops!'

ほとんどの例外名は、標準の例外名と同じように、「Error」で終わります。


クリーンアップ動作を定義する

try ステートメントには、状況に関係なく実行されるクリーンアップ動作を定義する別のオプションの句があります。 例:

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

上記の例では、try 句で例外が発生したかどうかに関係なく、finally 句が実行されます。

Try 句 (または、Except 句と else 句) で例外をキャッチするための例外がない場合、その例外は、finally 句の実行後に再度スローされます。

ここでは、より複雑な例を示します (同じ try ステートメントに、Except 句と Final 句が含まれています):

>>> try:
        raise KeyboardInterrupt
	finally:
        print('Goodbye, world!')
   
Goodbye, world!
KeyboardInterrupt

定義済みのクリーンアップ動作

一部のオブジェクトは、システムが正常に使用されているかどうかに関係なく、標準のクリーンアップ動作を定義しています必要に応じて、この標準のクリーンアップ動作が実行されます。

この例は、ファイルを開いてその内容を画面に出力しようとする例を示しています:

>>> 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.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

上記のコードの問題は、実行が完了してもファイルが開いたままになり、閉じられないことです。

ステートメントを含むキーワードは、ファイルなどのオブジェクトが使用後にクリーニング メソッドを正しく実行することを保証できます:

for line in open("myfile.txt"):
    print(line, end="")

上記のコードが実行された後、処理中に問題が発生した場合でも、ファイル f は常に閉じられます。