【Python入門】8章の演習プログラム

 ここでは、8章の知識を総合的に活用する「演習プログラム」を作成します。8章で学んだ内容を実際にコードを書いて動かすことで、基礎をしっかりと固め、さらに実践的なPythonプログラミングへとステップアップできるでしょう。

プログラムのダウンロード

 「ダウンロード」から、JupyterLab で実行できるサンプルプログラムがダウンロードできます。ファイルは、ESET Endpoint Securityでウイルスチェックをしておりますが、ダウンロードとプログラムの実行は自己責任でお願いいたします。

1.例外処理の基本

1.1.例外処理とは

 「例外」は予期しないエラーや問題が発生した状態を指し、例外処理とはプログラムを安全に動かし続けるための仕組みです。例えば、ファイルが存在しない場合にプログラムが途中で強制終了しないよう、例外処理でエラーを捕捉し、適切に対処できます。

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

1.2.例外処理を使わないエラー処理

 過去には関数の戻り値でエラーを表す手法も一般的でした。しかし、戻り値を常にチェックしなくてはならず、大規模化するとミスが増える・可読性が低下するなどの問題点が出てきます。そのため、Pythonでは例外処理によるエラー対応が推奨されます。

1.3.try文とexcept節の定義

 try ブロック内でエラーが起こると、対応する except 節の処理が実行されます。複数の例外が想定される場合は、複数の except 節を用意してそれぞれ対処できます。

try:
    with open('data.txt', 'r') as f:
        text = f.read()
except FileNotFoundError:
    print("ファイルが見つかりません。")
except PermissionError:
    print("ファイルを読み込む権限がありません。")

1.4.様々なexcept節の定義

 複数の例外クラスをタプルにまとめたり、except Exception as e: で詳細情報を取得したりできます。例外クラスの継承関係を把握しておくと、設計やデバッグがよりスムーズになります。

2.try文の構造と細かい制御

2.1.try文とfinally節

 finally 節は例外の発生・未発生に関わらず、必ず最後に実行させたい処理(ファイルやネットワーク接続のクローズなど)を記述するために使用します。

try:
    f = open('example.txt', 'r')
    # 何らかの処理
except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:
    f.close()  # 必ずクローズされる

2.2.try文とelse節

 else 節は「例外が発生しなかった場合にのみ」実行されるコードを記述します。エラー処理と通常の処理が明確に分離できるため、可読性が向上します。

2.3.例外を発生させるraise文

 raise 文を使うと、意図的に例外を起こしてエラー状態を作り出せます。たとえば、入力データが不正な場合に強制的にエラーを投げることで、誤った状態で後の処理を進めないようにできます。

def divide(a, b):
    if b == 0:
        raise ValueError("0 で割ることはできません。")
    return a / b

divide(10, 0)

3.内包表記

3.1.リストの内包表記

 リストを生成する際に for 文・条件式などを1行で書ける便利な機能です。可読性や実行速度の面でメリットがあります。

numbers = [i for i in range(5)]
numbers
# [0, 1, 2, 3, 4]

3.2.内包表記で多重ループさせる

for を複数並べることで、多重ループを簡潔に表現できます。

pairs = [(x, y) for x in range(2) for y in range(3)]
pairs
# [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

3.3.内包表記とif

リスト内包表記に if を組み合わせることで、取り込むデータをフィルタリングできます。

even_numbers = [i for i in range(10) if i % 2 == 0]
even_numbers
# [0, 2, 4, 6, 8]

3.4.内包表記と条件式

if-else を使って、条件に応じて異なる値を生成することも可能です。

labels = ["偶数" if i % 2 == 0 else "奇数" for i in range(5)]
labels
# ["偶数", "奇数", "偶数", "奇数", "偶数"]

4.ジェネレータと関数型プログラミング

4.1.ジェネレータ式

 リスト内包表記の []() に変えるだけで、値を逐次生成する「ジェネレータ式」になります。メモリ効率を重視したい場合に便利です。

gen = (i * i for i in range(5))
# gen はジェネレータオブジェクト
for val in gen:
    print(val)

4.2.ジェネレータ関数とyield文

 関数内で yield を使うと、イテレーションのたびに処理を一時停止して値を返す「ジェネレータ関数」が作れます。大量のデータを扱う場合やストリーム処理に効果的です。

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for num in countdown(3):
    print(num)  # 3, 2, 1

4.3.ラムダ式(関数型プログラミング)

 名前のない短い関数をその場で定義できる構文です。簡易的な演算やフィルタリング、ソートのキー指定などでよく使われます。

square = lambda x: x * x
print(square(3))  # 9

4.4.ソートのキーにラムダ式を指定する

 sorted() やリストの sort() メソッドに key パラメータを渡すことで、ソート基準を自由にカスタマイズできます。

data = ["apple", "banana", "cherry"]
sorted_data = sorted(data, key=lambda x: len(x))
print(sorted_data)  # 文字列の長さでソート

4.5.代入式

 Python 3.8以降では「ウォルラス演算子」(:=) が利用でき、式の途中で変数へ代入できるようになりました。

if (length := len(data)) > 2:
    print(f"要素が3つ以上あります (要素数: {length})")

4.6.デバッグやテストに使うassert文

 assert 文で条件式が偽の場合は AssertionError を発生させ、プログラムを停止できます。開発時に「ここは絶対にTrueであるべき」という前提を確認するために使われます。

def add_positive(a, b):
    assert a > 0 and b > 0, "引数は正の数である必要があります"
    return a + b

add_positive(-5, 0)

まとめ

 このように8章では「例外処理」「内包表記」「ジェネレータ」「ラムダ式」など、Pythonの便利かつ重要な機能を幅広く学んできました。次のステップとして、これらを活用する「演習プログラム」をぜひ実際に組んでみてください。自分なりのアイデアを追加しつつコードを書くことで、理解が一層深まるはずです。

 次の9章では、Pythonが標準で提供している強力な機能「組み込み関数」について解説します。学習の幅がさらに広がり、より効率的なプログラミングが可能になるでしょう。