にょっす速報🐮✋

Pythonにおける"yield"とは何か?

この記事の目次

Pythonにおけるyieldキーワードについて、この記事で詳しく解説します。yieldが提供する機能、その使用方法、およびコード例をもとにどのような役割を果たしているか見ていきます。


1. yieldとは何か?

Pythonでyieldキーワードは、関数の実行を一時停止して値を返し、関数の状態を保持したまま次の呼び出しで再開するために使われます。これにより、その関数は「ジェネレーター関数」として動作し、イテレーターを返すようになります。通常のreturnと異なり、yieldを使うと関数は中断と再開が可能となり、メモリ効率が向上します。


2. イテラブルとイテレーター

Pythonのfor...in...構文で反復できるオブジェクトはすべて「イテラブル」です。リスト、文字列、ファイルなどが含まれます。イテラブルは必要に応じてメモリにデータをすべて保持し、何度でもアクセスが可能です。

一方、「イテレーター」は一度きりの読み取り専用のオブジェクトです。値をその場で生成しながら、次に進むと前の値を保持しないため、特に大量データを扱う際にメモリの節約が可能です。


3. ジェネレーターとは?

ジェネレーターは、イテレーターの一種です。関数内でyieldが使用されると、その関数はジェネレーター関数になり、呼び出し時にジェネレーターオブジェクトを返します。ジェネレーターは値を逐次生成するため、メモリ効率が良く、大量のデータを扱う際に適しています。

例:

def create_generator():
    for i in range(3):
        yield i * i

この関数はジェネレーターを返し、ループを通じて0、1、4を生成します。yieldがあるため、ループごとに実行が中断・再開され、次の値が計算されるまで関数の状態が保持されます。


4. yieldの仕組み

関数にyieldがあると、関数を呼び出した際に即座にコードが実行されるわけではありません。まずはジェネレーターオブジェクトが返され、forループなどでそのオブジェクトが利用されると初めて、yieldに到達するまでのコードが実行されます。

このとき、yieldに到達するとその時点の値を返し、次にそのジェネレーターオブジェクトが呼び出されるまで関数は中断状態になります。呼び出しが続く限り、ジェネレーターは新しい値を順次生成しますが、ループが終了またはif条件によりyieldが呼ばれなくなると、ジェネレーターは空と見なされ終了します。


5. yieldを使った具体例:子候補を取得する関数

以下はyieldを利用した例です。このコードはツリー構造のデータを扱っており、条件に応じて子ノードを返します。

def _get_child_candidates(self, distance, min_dist, max_dist):
    if self._leftchild and distance - max_dist < self._median:
        yield self._leftchild
    if self._rightchild and distance + max_dist >= self._median:
        yield self._rightchild

この関数は条件に基づいて左右の子ノードをyieldし、結果をジェネレーターとして返します。呼び出し側ではこのジェネレーターを使い、子ノードを順次取得して処理を進めることができます。

呼び出し側コード例:

result, candidates = [], [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if min_dist <= distance <= max_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

このようにyieldを使うと、一度にすべての子ノードをリストとして返さずに順次返し、メモリ使用量を削減できます。また、extendメソッドはリストだけでなくジェネレーターも受け付けるため、効率的に次の子ノードを処理できます。


6. 応用:ジェネレーターの制御

以下のように、yieldを使ってリソースへのアクセスを制御することも可能です。

class Bank():
    crisis = False
    def create_atm(self):
        while not self.crisis:
            yield "$100"

この例では、ATMから現金を引き出す際にcrisisフラグによって操作を制限できます。


まとめ

yieldを活用すると、ジェネレーターを通じて大量のデータを効率よく扱うことが可能になります。イテラブルとしてのyieldの利点を理解することで、Pythonのメモリ効率をさらに高めることができます。特にツリー構造などの再帰的な処理や、逐次生成が必要な場合に役立ちます。

);

コメント(0件)


トピックス