はじめに
Pythonには例外処理の書き方がいくつかあります。
この記事では、例外処理の基本となるtry-except構文、ファイル操作などでお馴染みのwith文を紹介し、最後にコンテキストマネージャについて解説します。
Pythonコード多め・文章少なめです。
例外処理について初歩の初歩から始まり、Python独自の書き方まで解説します。
例外とは
IndexErrorやValueErrorなど、コードを動かすとエラーを起こすことがあります。これを 例外 と呼びます。
lst = [2, 4, 6, 8]
element = lst[4] # IndexError (リストの範囲外を見に行っているため)
word = "Python"
value = int(word) # ValueError (アルファベットをint型にしようとしたため)
try-except構文
try節, except節
例外が出るかもしれないとき、例外を出して急に終了しないようにしたいです。
try-exceptをつかえば、例外が出たときの対応も書けます。
import logging
lst = [2, 4, 6, 8]
idx = 4
try:
# 例外が出るかもしれない処理
element = lst[idx]
print(f"lstの{idx}番目の値は{element}です。")
except IndexErroe:
# IndexErrorが出たときの処理
logging.error({len(lst)=}, but {idx=}")
finally節
finally節を入れることもできます。この節では最後に必ず行う処理を書きます。
ファイルを開いたりデータベース接続をしたりした後、そのリソースを閉じるときによく使われます。
file_path = "test.txt"
file = None
try:
file = open(file_path, 'r') # ファイルを開く
content = file.read() # ファイルを読み込む
print(content)
except FileNotFoundError:
print(f"Error: {file_path} not found.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
# 最後に開いたファイルを閉じる
if file is not None:
file.close()
else節
最後にelse節を入れることもできます。この節では、try節が正常終了したときの処理を書きます。
else節をうまく使うと、可読性が向上します。
file_path = "test.txt"
file = None
try:
file = open(file_path, 'r') # ファイルを開く
except FileNotFoundError:
print(f"Error: {file_path} not found.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
else:
content = file.read() # ファイルを読み込む
print(content)
file.close()
finally:
print("called finally.")
with文
今度はデータベース接続をしたときのことを考えてみます。
import sqlite3
conn = None
try:
conn = sqlite3.connect('example.db') # データベースに接続
cursor = conn.cursor()
except sqlite3.Error as e:
print(f"An error occurred: {e}")
else:
# ここに100行以上の処理が入る (今回は省略)
finally:
if conn is not None:
conn.close()
else節にとても長いコードが入ることもあります。そんな中、本当にfinally節でちゃんと接続を閉じられるでしょうか?
そのようなことを防ぎコードを簡潔にしたのが with文です。
import sqlite3
with sqlite3.connect('example.db') as conn:
cursor = conn.cursor()
cursor.execute('SELECT * FROM users')
rows = cursor.fetchall()
for row in rows:
print(row)
conn.close()
のようにデータベース接続を閉じなくても、with節を抜けたら自動で閉じてくれます。
ファイルを開くときにもよく使われます。
try:
with open(file_path, 'r') as file:
content = file.read()
print(content)
except FileNotFoundError:
print("File not found.")
with文を使うと、try, finallyの処理を簡潔に書けます。
コンテキストマネージャ
open
関数のように、with文に入れられるものを コンテキストマネージャ と呼びます。
自作することもできます。
自作クラス
with節に入るときの処理は def __enter__()
, with節から出るときの処理は def __exit__()
に書きます。
class MyContextManager:
def __enter__(self):
print("Entering context")
return "MyContextManager returned"
def __exit__(self, exc_type, exc_value, exc_traceback):
print("Exiting context")
with MyContextManager() as cm:
print("with", cm)
Entering context
with MyContextManager returned
Exiting context
contextmanagerデコレータ
クラスよりも簡潔に自作できるのがcontextmanagerデコレータです。
from contextlib import contextmanager
@contextmanager
def my_context_manager():
print("Entering context")
yield "MyContextManager returned"
print("Exiting context")
with my_context_manager() as cm:
print("with", cm)
Entering context
with MyContextManager returned
Exiting context
with節に入るときに、yield
よりも前に書いた処理が呼ばれます。
cmの値は yield
で返す値です。
with節から出るときに、yield
よりも後に書いた処理が呼ばれます。
おわりに
ファイル操作やデータベース接続など、例外処理を使う場面は多いです。
これらの技術を適切に活用することで、コードの安全性と可読性が向上します。