Yomiage
メニュー

Python実践講座 09:イテレータとジェネレータで逐次処理する

更新 2026/9/27 6:22:11 公開

投稿者: しゅりりん

到達点は、全件を保持せずに処理する流れを作ることです。前提は第04・07回です。

必要になるまで作らない

イテラブルはforで順に取り出せるもの、イテレータはその取り出し位置を持つものです。ジェネレータ関数はyieldで一つずつ値を返し、次に求められるまで処理を中断します。

def valid_minutes(lines):
    for line_number, text in enumerate(lines, start=1):
        stripped = text.strip()
        if not stripped:
            continue
        value = int(stripped)
        if value < 0:
            raise ValueError(f"{line_number}行目が負です")
        yield value


values = valid_minutes(["25", "", "15", "30"])
print(next(values))
print(sum(values))
print(list(values))
squares = (number * number for number in range(5))
print(list(squares))

main.pyで実行すると25、45、空のリスト、0・1・4・9・16が出ます。nextで取り出した25は消費済みなので、sumには含まれません。最後まで消費したイテレータをもう一度読んでも最初には戻りません。

遅延すると失敗する時点も変わる

ジェネレータを作った瞬間には、関数本体がまだ実行されていません。不正な行の例外は、その行を読み進めた時点で発生します。tryを置く場所は生成の行だけでなく、反復する処理を含める必要があります。

ファイルの行をyieldする関数は、誰がファイルを閉じるかにも注意します。閉じたファイルを後で読もうとするジェネレータを返す設計は壊れます。呼び出し側でwithの中に反復を置くなど、資源の寿命と利用期間を合わせます。

ジェネレータなら必ずメモリ使用量が小さくなるわけでもありません。最後にlistへ変換したり、全件のsortedを行ったりすれば全件保持が必要です。集計が合計だけなら一つの累積値、上位数件なら限定サイズのデータ構造というように、目的から考えます。

練習と解答

練習:学習時間の平均を、全件をリストへ変換せずに求めます。空入力も扱ってください。

解答:ループで合計と件数を同時に増やします。件数が0ならNoneなど明示的な不在を返し、そうでなければ合計を件数で割ります。同じイテレータにsumを二回かけて件数を数えようとしても、二回目には要素が残っていません。

公式資料

イテレータとジェネレータを参照できます。


Python全20回の目次 | 前の回 | 次の回

このブラウザでは Web Speech API が利用できません。

1 / 16 · 停止中