注目キーワード

【Python】yieldの基本的な使い方を確認する

リストのデータを1つずつ処理する際に、forを使ってループすることはよくあると思います。このように1つずつデータを処理するデータを保持する仕組みはイテレータと呼ばれ、いろんなところで使われています。

特に大規模なリストを処理するとき、データを一度メモリ上に乗せなければならないためメモリ消費量が大きくなります。これを解消するためにデータを一つずつ生成して処理することができる仕組みがジェネレータと呼ばれ、Pythonでは yield を使って実装することができます。こちらの記事で、yieldの基本的な使い方を確認します。

リストの反復処理とyieldの使い方

リストのデータを1つずつ処理する場合の様々な実装方法について見てみます。

サンプルソース(反復処理とyieldの使い方)

サンプルの実装です。

サンプルでは [0, 1, 2, 3, 4, 5] のデータをプリントするために、3つの方法を実装しました。

1つ目は通常のforを使って、リストを1つずつ処理する方法です。

2つ目と3つ目はyieldを利用する方法です。2つ目の方法では、dataの1つずつの要素を yield i と書き、ジェネレータ(イテレータを生成する仕組み)を作成しています。こうして作成したジェネレータは、2つ目の出力方法では直接for文の中で、3つ目の出力方法では一旦 data_gen という変数に格納された上でfor文で利用されます。

実行結果

結果はどの方法でも同じ出力が得られます。

3つのfor文の反復方法で得られた同じ出力結果

Pythonのyieldを使ってFizzBuzzを書いてみる

基本的な処理としてFizzBuzzがありますが、yieldを使ってFizzBuzを書いてみましょう。ここでは yield の動作を確認するために、次のサンプルコードを実装しました。

サンプルソース(yieldとFizzBuzz)

サンプルの実装です。

2つのリストの範囲(data1: 1から19、data2: 101から119)に対して、FizzBuzzの処理を行います。

実装した fizz_buzz_gen() の中に yield が使われています。data1 の処理を終えたら、次にdata2 を処理し、FizzBuzzで出力すべき文字列をそれぞれ yield で返しています。

最後に作成したジェネレータ関数を呼び出し、出力しています。実装した fizz_buzz_gen の中身では data1 から data2 の処理へ続いていきますが、呼び出す側から見たときには単にfor文を1つ書くだけで動作します。

実行結果

実行結果は次のようになります。一度FizzBuzzの処理が19までいき、101から再開する様子が分かるかと思います。

スポンサーリンク

yieldを用いて実装したFizzBuzzの実行(1〜19と101〜119)

今回示した例ではメモリの使用量については削減された効果は確認していませんが、大規模なリストなどを処理し、条件によって値を書き換えるFizzBuzzのような処理をする際には、一度yieldに置き換えて使ってみると処理がうまくいくかもしれません。試してみてくださいね。