Python入門 第10回:例外処理(try-except構文)

Python入門 第10回:例外処理(try-except構文) Python

はじめに

プログラムを実行していると、入力された値が想定と違っていたり、指定したファイルが存在しなかったりして、エラーが発生することがあります。

エラーが発生したとき、何も対策をしていなければ、その時点でプログラムの処理が停止してしまいます。

しかし、Pythonの「例外処理」を使用すると、エラーが発生した場合の処理をあらかじめ決めておくことができます。

今回は、Pythonで例外処理を行うためのtry-except構文について解説します。


例外処理とは

例外処理とは、プログラムの実行中に問題が発生した場合に、その問題へ対応するための仕組みです。

例えば、次のような場面でエラーが発生する可能性があります。

  • 数値を入力してほしい場所で文字列が入力された
  • 0で割り算をしようとした
  • 存在しないファイルを開こうとした
  • リストに存在しない位置の要素を取得しようとした
  • 辞書に存在しないキーを指定した

通常、エラーが発生すると、Pythonはエラーメッセージを表示してプログラムを停止します。

例外処理を使用すると、エラーが発生した場合でも、プログラムを突然停止させずに別の処理を実行できます。

例えば、ユーザーが正しくない値を入力した場合に、次のようなメッセージを表示できます。

数値を入力してください。

例外処理は、プログラムを安定して動作させるために重要な機能です。


エラーと例外の違い

Pythonで発生する問題には、大きく分けて「構文エラー」と「例外」があります。

構文エラー

構文エラーは、Pythonの文法が間違っている場合に発生します。

例えば、次のコードでは、if文の末尾にコロンがありません。

age = 20

if age >= 18
    print("成人です")

このコードを実行すると、SyntaxErrorが発生します。

SyntaxError: expected ':'

構文エラーがある場合、プログラムを正しく実行できません。

そのため、コードそのものを修正する必要があります。

例外

例外は、Pythonの文法には問題がないものの、プログラムの実行中に問題が発生した場合に起こります。

次のコードでは、数値を0で割っています。

result = 10 / 0

print(result)

Pythonの文法としては正しいコードですが、0で割り算を行うことはできません。

そのため、実行するとZeroDivisionErrorが発生します。

ZeroDivisionError: division by zero

このような実行中のエラーに対応するために、例外処理を使用します。


try-except構文の基本

Pythonで例外処理を行う場合は、tryexceptを使用します。

基本的な書き方は次のとおりです。

try:
    エラーが発生する可能性のある処理
except:
    エラーが発生した場合の処理

tryブロックには、通常実行したい処理を記述します。

tryブロック内でエラーが発生すると、それ以降の処理は実行されず、exceptブロックへ移動します。

0で割り算を行う例

次のコードを見てみましょう。

try:
    result = 10 / 0
    print(result)
except:
    print("エラーが発生しました")

実行結果は次のようになります。

エラーが発生しました

10 / 0の部分でエラーが発生するため、次の処理は実行されません。

print(result)

その代わりに、exceptブロックの処理が実行されます。

エラーが発生しない場合

次のコードでは、0以外の数値で割り算を行っています。

try:
    result = 10 / 2
    print(result)
except:
    print("エラーが発生しました")

実行結果は次のとおりです。

5.0

エラーが発生しなかったため、exceptブロックは実行されません。


発生する例外の種類を指定する

exceptには、処理したい例外の種類を指定できます。

try:
    エラーが発生する可能性のある処理
except 例外の種類:
    指定した例外が発生した場合の処理

例外の種類を指定することで、エラーの原因に応じて適切な処理を実行できます。

ZeroDivisionError

ZeroDivisionErrorは、0で割り算を行った場合に発生します。

try:
    number = 10
    result = number / 0
except ZeroDivisionError:
    print("0で割ることはできません")

実行結果は次のとおりです。

0で割ることはできません

ValueError

ValueErrorは、値の形式が正しくない場合などに発生します。

例えば、文字列を整数へ変換してみます。

number = int("Python")

"Python"は整数へ変換できないため、ValueErrorが発生します。

例外処理を追加すると、次のように記述できます。

try:
    number = int("Python")
    print(number)
except ValueError:
    print("整数へ変換できない値です")

実行結果は次のとおりです。

整数へ変換できない値です

TypeError

TypeErrorは、データ型に対応していない処理を行った場合に発生します。

例えば、整数と文字列をそのまま足すことはできません。

try:
    result = 10 + "20"
except TypeError:
    print("異なるデータ型をそのまま足すことはできません")

実行結果は次のとおりです。

異なるデータ型をそのまま足すことはできません

IndexError

IndexErrorは、リストに存在しないインデックスを指定した場合に発生します。

fruits = ["りんご", "バナナ", "みかん"]

try:
    print(fruits[5])
except IndexError:
    print("指定した位置に要素がありません")

リストの要素は3個しかないため、インデックス5の要素は存在しません。

実行結果は次のとおりです。

指定した位置に要素がありません

KeyError

KeyErrorは、辞書に存在しないキーを指定した場合に発生します。

user = {
    "name": "田中",
    "age": 25
}

try:
    print(user["address"])
except KeyError:
    print("指定したキーは存在しません")

実行結果は次のとおりです。

指定したキーは存在しません

FileNotFoundError

FileNotFoundErrorは、存在しないファイルを開こうとした場合に発生します。

try:
    file = open("sample.txt", "r", encoding="utf-8")
except FileNotFoundError:
    print("ファイルが見つかりません")

sample.txtが存在しない場合、次のように表示されます。

ファイルが見つかりません

複数の例外を処理する

1つの処理で、複数種類の例外が発生する可能性があります。

その場合は、複数のexceptを記述できます。

exceptを複数記述する

次のプログラムでは、入力された数値を使って割り算を行います。

try:
    number = int(input("割る数を入力してください:"))
    result = 100 / number
    print(f"計算結果:{result}")

except ValueError:
    print("整数を入力してください")

except ZeroDivisionError:
    print("0を入力することはできません")

数値ではなく文字列を入力した場合は、ValueErrorが発生します。

割る数を入力してください:Python
整数を入力してください

0を入力した場合は、ZeroDivisionErrorが発生します。

割る数を入力してください:0
0を入力することはできません

正しい数値を入力した場合は、計算結果が表示されます。

割る数を入力してください:4
計算結果:25.0

このように、例外の種類ごとに異なる処理を実行できます。

複数の例外をまとめて処理する

複数の例外で同じ処理を行いたい場合は、例外をタプルでまとめて指定できます。

try:
    number = int(input("割る数を入力してください:"))
    result = 100 / number
    print(result)

except (ValueError, ZeroDivisionError):
    print("正しい数値を入力してください")

ValueErrorまたはZeroDivisionErrorが発生すると、同じメッセージが表示されます。

ただし、エラーの原因ごとに異なる案内を表示したい場合は、exceptを分けて記述した方が分かりやすくなります。


例外の内容を確認する

例外が発生したとき、どのような問題が発生したのかを詳しく確認したい場合があります。

その場合は、asを使用して例外の内容を変数へ代入します。

try:
    エラーが発生する可能性のある処理
except 例外の種類 as 変数名:
    例外が発生した場合の処理

次の例では、発生した例外の内容をerrorという変数へ代入しています。

try:
    result = 10 / 0
except ZeroDivisionError as error:
    print("エラーが発生しました")
    print(error)

実行結果は次のとおりです。

エラーが発生しました
division by zero

変数名にはeがよく使用されます。

try:
    number = int("abc")
except ValueError as e:
    print(f"エラー内容:{e}")

実行結果は次のようになります。

エラー内容:invalid literal for int() with base 10: 'abc'

例外の内容を表示することで、プログラムの問題を調査しやすくなります。

ただし、一般ユーザー向けの画面では、Pythonの詳しいエラーメッセージをそのまま表示するよりも、分かりやすい文章へ置き換えた方がよい場合があります。


elseを使用する

例外処理では、tryexceptに加えてelseを使用できます。

elseブロックは、tryブロックで例外が発生しなかった場合に実行されます。

基本的な書き方は次のとおりです。

try:
    エラーが発生する可能性のある処理
except 例外の種類:
    エラーが発生した場合の処理
else:
    エラーが発生しなかった場合の処理

次の例では、入力された文字列を整数へ変換します。

try:
    number = int(input("整数を入力してください:"))
except ValueError:
    print("整数以外の値が入力されました")
else:
    print(f"入力された数値は{number}です")

整数を入力した場合は、elseブロックが実行されます。

整数を入力してください:10
入力された数値は10です

文字列を入力した場合は、exceptブロックが実行されます。

整数を入力してください:Python
整数以外の値が入力されました

tryブロックには、できるだけエラーが発生する可能性のある処理だけを記述します。

エラーが発生しなかった場合に行う処理は、elseブロックへ分けると、コードの目的が分かりやすくなります。


finallyを使用する

finallyブロックは、例外が発生したかどうかに関係なく、必ず実行されます。

基本的な書き方は次のとおりです。

try:
    エラーが発生する可能性のある処理
except 例外の種類:
    エラーが発生した場合の処理
finally:
    必ず実行する処理

次の例を見てみましょう。

try:
    number = int(input("整数を入力してください:"))
    print(f"入力された数値:{number}")
except ValueError:
    print("整数を入力してください")
finally:
    print("処理を終了します")

整数を入力した場合の実行結果は次のとおりです。

整数を入力してください:10
入力された数値:10
処理を終了します

文字列を入力した場合でも、finallyブロックは実行されます。

整数を入力してください:Python
整数を入力してください
処理を終了します

finallyは、ファイルやネットワーク接続など、使用後に必ず終了処理が必要な場合に利用されます。

例えば、開いたファイルを閉じる処理などです。

file = None

try:
    file = open("sample.txt", "r", encoding="utf-8")
    content = file.read()
    print(content)

except FileNotFoundError:
    print("ファイルが見つかりません")

finally:
    if file is not None:
        file.close()
        print("ファイルを閉じました")

ただし、Pythonでファイルを扱う場合は、通常はwith文を使用する方法が推奨されます。

try:
    with open("sample.txt", "r", encoding="utf-8") as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("ファイルが見つかりません")

with文を使用すると、処理が終了したときにファイルが自動的に閉じられます。


try-except-else-finallyを組み合わせる

tryexceptelsefinallyは、組み合わせて使用できます。

try:
    number = int(input("割る数を入力してください:"))
    result = 100 / number

except ValueError:
    print("整数を入力してください")

except ZeroDivisionError:
    print("0で割ることはできません")

else:
    print(f"計算結果:{result}")

finally:
    print("計算処理を終了します")

正しい数値を入力した場合は、次のように表示されます。

割る数を入力してください:5
計算結果:20.0
計算処理を終了します

0を入力した場合は、次のように表示されます。

割る数を入力してください:0
0で割ることはできません
計算処理を終了します

文字列を入力した場合は、次のように表示されます。

割る数を入力してください:Python
整数を入力してください
計算処理を終了します

それぞれの役割は次のとおりです。

  • try:例外が発生する可能性のある処理
  • except:例外が発生した場合の処理
  • else:例外が発生しなかった場合の処理
  • finally:例外の有無に関係なく必ず実行する処理

すべてを毎回使用する必要はありません。

必要なものだけを組み合わせて使用します。


raiseで例外を発生させる

Pythonが自動的に発生させる例外だけでなく、プログラムの条件に応じて自分で例外を発生させることもできます。

例外を発生させる場合は、raiseを使用します。

raise 例外の種類("エラーメッセージ")

例えば、年齢に負の値が指定された場合に例外を発生させてみます。

age = -5

if age < 0:
    raise ValueError("年齢には0以上の値を指定してください")

実行すると、次のようなエラーが表示されます。

ValueError: 年齢には0以上の値を指定してください

raiseで発生させた例外は、try-exceptで処理できます。

try:
    age = int(input("年齢を入力してください:"))

    if age < 0:
        raise ValueError("年齢には0以上の値を指定してください")

except ValueError as e:
    print(f"入力エラー:{e}")

else:
    print(f"年齢は{age}歳です")

負の値を入力すると、次のように表示されます。

年齢を入力してください:-5
入力エラー:年齢には0以上の値を指定してください

正しい値を入力した場合は、次のようになります。

年齢を入力してください:25
年齢は25歳です

raiseを使用すると、プログラム独自の条件に対してエラーを発生させられます。


実用的な例外処理

ここでは、例外処理を使用した実用的なプログラムを紹介します。

正しい数値が入力されるまで繰り返す

while文と例外処理を組み合わせると、正しい値が入力されるまで入力処理を繰り返せます。

while True:
    try:
        number = int(input("整数を入力してください:"))
        break
    except ValueError:
        print("整数ではありません。もう一度入力してください。")

print(f"入力された数値は{number}です")

文字列を入力した場合は、再入力を求めます。

整数を入力してください:abc
整数ではありません。もう一度入力してください。
整数を入力してください:10
入力された数値は10です

int()による変換が成功した場合は、breakによって繰り返し処理を終了します。

安全に割り算を行う

次のプログラムでは、2つの値を入力して割り算を行います。

try:
    number1 = float(input("割られる数を入力してください:"))
    number2 = float(input("割る数を入力してください:"))

    result = number1 / number2

except ValueError:
    print("数値を入力してください")

except ZeroDivisionError:
    print("0で割ることはできません")

else:
    print(f"計算結果:{result}")

数値以外が入力された場合と、0が入力された場合を別々に処理しています。

リストから安全に要素を取得する

fruits = ["りんご", "バナナ", "みかん"]

try:
    index = int(input("取得する位置を入力してください:"))
    fruit = fruits[index]

except ValueError:
    print("整数を入力してください")

except IndexError:
    print("指定した位置に要素がありません")

else:
    print(f"選択された果物:{fruit}")

このプログラムでは、次の2種類の例外が発生する可能性があります。

  • 入力値が整数ではない場合のValueError
  • リストに存在しない位置を指定した場合のIndexError

ファイルを読み込む

filename = input("読み込むファイル名を入力してください:")

try:
    with open(filename, "r", encoding="utf-8") as file:
        content = file.read()

except FileNotFoundError:
    print("指定したファイルが見つかりません")

except PermissionError:
    print("ファイルを開く権限がありません")

else:
    print("ファイルの内容を表示します")
    print(content)

ファイルが存在しない場合はFileNotFoundError、アクセス権限がない場合はPermissionErrorを処理しています。


例外処理を使用するときの注意点

例外処理は便利ですが、使用方法によってはエラーの原因が分かりにくくなることがあります。

exceptだけを記述しすぎない

次のように、例外の種類を指定せずにexceptを記述することもできます。

try:
    result = 10 / 0
except:
    print("エラーが発生しました")

この書き方では、さまざまな例外をまとめて処理できます。

しかし、どのような例外が発生したのか分かりにくくなります。

可能な限り、処理したい例外の種類を指定しましょう。

try:
    result = 10 / 0
except ZeroDivisionError:
    print("0で割ることはできません")

Exceptionでまとめて処理する

予測できない一般的な例外を処理したい場合は、Exceptionを指定できます。

try:
    number = int(input("整数を入力してください:"))
    result = 100 / number

except Exception as e:
    print(f"エラーが発生しました:{e}")

Exceptionは多くの一般的な例外を処理できます。

ただし、すべての処理をExceptionだけでまとめてしまうと、エラーの種類に応じた対応ができません。

次のように、予想できる例外を先に個別で処理し、最後にExceptionを記述する方法があります。

try:
    number = int(input("整数を入力してください:"))
    result = 100 / number

except ValueError:
    print("整数を入力してください")

except ZeroDivisionError:
    print("0を入力することはできません")

except Exception as e:
    print(f"予期しないエラーが発生しました:{e}")

exceptは、上から順番に確認されます。

そのため、広い範囲の例外を処理するExceptionは、最後に記述します。

tryブロックを広くしすぎない

次のコードでは、多くの処理がtryブロックに含まれています。

try:
    number = int(input("整数を入力してください:"))
    result = number * 2
    message = f"計算結果は{result}です"
    print(message)
except ValueError:
    print("整数を入力してください")

この程度の処理であれば問題ありませんが、tryブロックが長くなると、どの処理で例外が発生したのか分かりにくくなります。

例外が発生する可能性のある処理だけをtryブロックへ記述し、それ以外をelseへ分けると分かりやすくなります。

try:
    number = int(input("整数を入力してください:"))
except ValueError:
    print("整数を入力してください")
else:
    result = number * 2
    message = f"計算結果は{result}です"
    print(message)

エラーを無視しない

次のように、passを使用すると、例外が発生しても何も処理せずに進められます。

try:
    number = int("Python")
except ValueError:
    pass

ただし、この書き方では、エラーが発生したことが分からなくなってしまいます。

特別な理由がない限り、メッセージを表示したり、ログを記録したりして、エラーの発生を確認できるようにしましょう。


まとめ

今回は、Pythonの例外処理について解説しました。

例外処理を使用すると、プログラムの実行中にエラーが発生しても、プログラムを突然停止させずに対応できます。

基本的な書き方は次のとおりです。

try:
    エラーが発生する可能性のある処理
except 例外の種類:
    エラーが発生した場合の処理

今回の重要なポイントをまとめます。

  • tryには、例外が発生する可能性のある処理を記述する
  • exceptには、例外が発生した場合の処理を記述する
  • exceptには、処理する例外の種類を指定できる
  • 複数のexceptを使用して、例外ごとに処理を分けられる
  • asを使用すると、例外の詳しい内容を取得できる
  • elseは、例外が発生しなかった場合に実行される
  • finallyは、例外の有無に関係なく必ず実行される
  • raiseを使用すると、自分で例外を発生させられる
  • tryブロックには、必要な処理だけを記述する
  • 可能な限り、処理する例外の種類を明確にする

例外処理は、ユーザーから値を受け取るプログラムや、ファイルを操作するプログラムでは特に重要です。

最初は難しく感じるかもしれませんが、まずはtryexceptの基本的な形から使ってみましょう。

次回は、Pythonでファイルを読み書きする方法について解説します。

コメント

タイトルとURLをコピーしました