python yield

python Python

yield はPythonのジェネレータ関数を定義するために使用されるキーワードです。ジェネレータ関数は、イテレータを簡単に作成する方法を提供し、特に大量のデータを扱う際にメモリ効率が良いという利点があります。

通常の関数は、一度にすべての処理を実行し、単一の値を返すか、何も返しません。一方、ジェネレータ関数は yield を使用することで、値を「生成」し、その状態を一時停止することができます。次に値が要求されたときに、中断した場所から実行を再開し、次の値を生成します。

必要になったときにだけ値を生成するため(遅延評価)、すべてのデータをメモリにロードする必要がありません。これは、特に巨大なデータセットや無限のシーケンスを扱う場合に非常に重要です。

基本的な使い方

Python
def sample_generator():
    print("generate #1")
    yield 1
    print("generate #2")
    yield 2
    print("generate #3")
    yield 3
    print("generate 完了")

# ジェネレータオブジェクトを作成
gen = sample_generator()

print("next()呼び出し#1")
print(next(gen))
print("next()呼び出し#2")
print(next(gen))
print("next()呼び出し#3")
print(next(gen))

print("ジェネレータをループで呼び出し")
for value in sample_generator():
    print(value)

# next()呼び出し#1
# generate #1
# 1
# next()呼び出し#2
# generate #2
# 2
# next()呼び出し#3
# generate #3
# 3
# ジェネレータをループで呼び出し
# generate #1
# 1
# generate #2
# 2
# generate #3
# 3
# generate 完了

この例では、next(gen) が呼び出されるたびに、simple_generator 関数が実行され、yield ステートメントで一時停止します。forループで回すと、最後のprint(“generate 完了”)が呼び出されます。

無限シーケンス

Python
def infinite_numbers():
    num = 0
    while True:
        yield num
        num += 1

# 無限のジェネレータなので、必要な数だけ取り出す
gen = infinite_numbers()

print("最初の5つの無限数列:")
for _ in range(5):
    print(next(gen))

print("-" * 30)

# 特定の条件で停止する例
print("偶数のみを生成し、10000より小さいもの:")
even_generator = (n for n in infinite_numbers() if n % 2 == 0) # ジェネレータ内包表記
count = 0
for num in even_generator:
    if num >= 10000:
        break
    print(num)
    count += 1
# 最初の5つの無限数列:
# 0
# 1
# 2
# 3
# 4
# ------------------------------
# 偶数のみを生成し、10000より小さいもの:
# 0
# 2
# 4
# ...
# 9994
# 9996
# 9998

この例のinfini_numbers( )のように、無限のジェネレータを使って巨大なシーケンスを生成できるのはジェネレータの大きな利点です。通常の関数では、無限ループに陥ってしまうためこのような処理はできません。

大きなファイルの読み込み

Python
import os

# テスト用の巨大ファイルを準備
file_name = "_large_file_.txt"
if not os.path.exists(file_name):
    print(f"{file_name} を作成中...")
    with open(file_name, "w", encoding="utf-8") as f:
        for i in range(100000):
            f.write(f"これは{i}行目のデータです。\n")
    print(f"{file_name} の作成が完了しました。")

# ファイルを読み込むジェネレータ
def read_large_file(file_path):
    print(f"ファイル {file_path} の読み込みを開始します...")
    with open(file_path, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip() # 改行コードを除去してyield

line_count = 0
for line in read_large_file(file_name):
    if line_count < 5: # 最初の5行だけ表示
        print(line)
    line_count += 1
    if line_count % 10000 == 0:
        print(f"{line_count}行目まで処理しました...")

# ファイル _large_file_.txt の読み込みを開始します...
# これは0行目のデータです。
# これは1行目のデータです。
# これは2行目のデータです。
# これは3行目のデータです。
# これは4行目のデータです。
# ...
# 60000行目まで処理しました...
# 70000行目まで処理しました...
# 80000行目まで処理しました...
# 90000行目まで処理しました...
# 100000行目まで処理しました...

この例では、ファイル全体をメモリにロードせず、必要な時に1行ずつ読み込むためにメモリ効率が良く、巨大なファイルに対応することができます。

コメント

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