Python の yield from で委譲する
yield from は、別のイテラブルやジェネレータの要素をすべて委譲して yield するための構文です。ネストしたジェネレータを扱う際にコードを簡潔にできます。
yield from の基本
yield from を使うと、イテラブルの各要素を順番に yield できます。
def generator():
yield from [1, 2, 3]
yield from "ABC"
for value in generator():
print(value)
# 1, 2, 3, A, B, C
yield from を使わない場合との比較
yield from がない場合、for ループを書く必要があります。
yield from を使う
yield from iterable
コードが簡潔になる
for ループを使う
for item in iterable:
yield item
冗長になる
# yield from なし
def flatten_without():
for item in [1, 2, 3]:
yield item
for item in [4, 5, 6]:
yield item
# yield from あり
def flatten_with():
yield from [1, 2, 3]
yield from [4, 5, 6]
ネストしたリストのフラット化
yield from の典型的な使い方は、入れ子になった構造をフラットにすることです。
def flatten(nested):
for item in nested:
if isinstance(item, list):
yield from flatten(item) # 再帰的に委譲
else:
yield item
nested = [1, [2, 3, [4, 5]], 6, [7]]
print(list(flatten(nested)))
# [1, 2, 3, 4, 5, 6, 7]
サブジェネレータへの委譲
yield from は別のジェネレータに処理を委譲する際にも使います。
def sub_generator():
yield "sub 1"
yield "sub 2"
return "サブ完了"
def main_generator():
yield "main 開始"
result = yield from sub_generator()
print(f"受け取った値: {result}")
yield "main 終了"
for value in main_generator():
print(value)
# main 開始
# sub 1
# sub 2
# 受け取った値: サブ完了
# main 終了
サブジェネレータの return 値は、yield from 式の結果として受け取れます。
複数のデータソースを連結
複数のイテラブルを順番に処理するジェネレータを簡単に作れます。
def chain(*iterables):
for it in iterables:
yield from it
result = list(chain([1, 2], "ab", (10, 20)))
print(result) # [1, 2, 'a', 'b', 10, 20]
注意点
yield from は、サブジェネレータが StopIteration を送出するまで、すべての値を委譲します。途中で制御を戻すことはできないため、条件付きで中断したい場合は通常の for ループと yield を組み合わせてください。