yield fromの概要

Python 3.3で導入されたyield from構文は、ジェネレーターやコルーチン間で効率的に処理を委譲するためのツールです。これにより、サブジェネレーターからの値や例外を自動的に受け渡すことができ、複雑なforループの代わりに簡潔なコードを記述できます。

使い方と動作原理

通常、ジェネレーターをネストして使用する場合、サブジェネレーターから値を手動で反復する必要があります。以下の例を見てみましょう。

def generator():
    for i in range(5):
        yield i
def outer():
    for value in generator():
        yield value

このコードは、サブジェネレーターgeneratorから値をouterで再度反復して返します。yield fromを使うと、これを次のように簡素化できます。

def outer():
    yield from generator()

この変更により、反復処理の手間が省かれ、可読性が向上します。

非同期I/Oとコルーチン

yield fromは非同期プログラミングでも役立ちます。コルーチン間でデータを送受信する際や例外を扱うとき、yield fromを使うことで双方向の通信を簡潔に実装できます。また、ネストされたジェネレーターやコルーチンが完了したときに適切に処理を終了する仕組みも提供します。

async def handle_client(reader, writer):
    data = await reader.read(100)
    writer.write(data)
    await writer.drain()
    writer.close()

上記の例はyield fromに似た非同期I/Oの例であり、yield fromはこれと同様にコルーチンを使ったプログラムで簡潔な処理を可能にします。

実用例

再帰的なデータ構造の処理

再帰的なジェネレーターを使って、ネストされたデータ構造を探索するケースがあります。yield fromを使うと、次のように簡単に記述できます。

def traverse_tree(node):
    if not node.children:
        yield node
    for child in node.children:
        yield from traverse_tree(child)

この例では、木構造の全てのリーフノードを再帰的に取得しています。

まとめ

yield fromは、ジェネレーターの委譲や非同期処理を効率化し、Pythonコードを簡潔かつ効率的にします。特に、複雑なジェネレーターの操作やネストされた処理をシンプルにする効果があります。