元セブ島在住のエンジニアの僕「Tommy」が、プログラミング・英語・セブ事情を発信するブログ

Tommy's blog

【Python】yieldをfor文で使う方法【→プログラミング初心者向け】

2月 5, 2020

プログラム女子
ネットで見るPythonの「yield」って何なんですか?
関数を途中で止めて戻す処理だね。ここでは、「yield」がどんな使われ方をするのか説明するよ。
Tommy

この記事で分かること

  • Pythonのyield文とは何かが分かる
  • Pythonのyield文の使い方が分かる

Pythonのyieldをfor文で使う方法の概要

この記事では、Pythonの「yield」文の使い方を解説します。「yield」を使う場合には、合わせて「for」文を使うことが多いですが、そのようなオーソドックスな「yield」文を使った例を説明します。

その後、「yield」がどのように動作するのかを把握する為に、「yield」を含む関数の戻りのタイプと、そのタイプの使い方をサンプルプログラムを見ながら説明します。

この記事では、Pythonの「yield」文の使い方を解説します。「yield」を使う場合には、合わせて「for」文を使うことが多いですが、そのようなオーソドックスな「yield」文を使った例を説明します。

その後、「yield」がどのように動作するのかを把握する為に、「yield」を含む関数の戻りのタイプと、そのタイプの使い方をサンプルプログラムを見ながら説明します。

Pythonのyieldをfor文で使う方法の前提環境

Pythonの「yield」の使い方の前提の環境は、下の記事で説明している私の環境と同じ環境で確認しています。

また、レンタルサーバなどのLinuxサーバを使っている場合は、下の記事でプログラミングする環境の作り方を説明しています。もし、まだプログラムする環境ができていない方は、先にこちらの記事を読んで、プログラミングできる環境をつくることをおすすめします。

Pythonのyieldをfor文で使うサンプルプログラム

サンプルプログラムでは、「yield」の動作を確認するために、「For文を使った例」と「For文を使わない例」の2つのプログラムを説明します。

yieldの使い方のサンプルコード(for文を使った例)

ここでは、yieldの動作を確認する為に、8と2の四則演算の結果をyieldで返す関数 「test_yield」を次のサンプルプログラムのように定義します。

def test_yield():

	a = 8
	b = 2

	yield a+b
	yield a-b
	yield a*b
	yield a/b

  1. 「test_yield」を宣言する
  2. 変数「a」を8で初期化する
  3. 変数「b」を2で初期化する
  4. 変数「a」と変数「b」を足した結果をyieldで返す
  5. 変数「a」と変数「b」を引いた結果をyieldで返す
  6. 変数「a」と変数「b」を掛けた結果をyieldで返す
  7. 変数「a」と変数「b」を割った結果をyieldで返す

「yield」 文で書かれた関数を呼び出すと、その関数の返り値としては、 generator(ジェネレータ)という種類の戻りが返却されます。For文の1回目のループでは1つ目の「yield」に指定されている値が返却され、次の2回目のループでは、2つ目の 「yield」で指定されている値が返却されいく。という具合に処理されます。

なので、戻りが「yield」で指定されている関数呼び出し側でFor文を使う理由は、複数回に渡って戻り値を戻すという正確があるからです。

「yield」で複数の戻り値が返却されているかを確認する為に、下のMainの処理では、関数「test_yield」の戻りのタイプの表示と、関数「test_yield」の戻りをFor文で要素を1つずつ表示しています。

if __name__ == '__main__':

	print(type(test_yield()))
	
	for ele in test_yield():
		print(ele)

  1. 関数「test_yield」の戻りの型を表示する。
  2. 関数「test_yield」で得た値を変数「ele」に代入しながら、for文で「ele」を表示する。

結果は、下のようになり、関数 __test_yield__ の戻りのタイプは「generator」となっており、8と2の足し算、引き算、掛け算、割り算の結果がそれぞれ表示されています。

$ python test.py
<type 'generator'>
10
6
16
4

yieldの使い方のサンプルコード(for文を使わない例)

次は、For文を使わない例を考えてみましょう。次のサンプルプログラムように、関数「test_yield」の戻りを一旦 「gen」という変数に入れます。その後、generator変数の関数「next()」を呼び出して、中断していた「test_yield」の処理を再開します。逐次yieldされた値をprint文で表示します。

if __name__ == '__main__':

	print(type(test_yield()))

	gen = test_yield()
	print(gen.next())
	print(gen.next())
	print(gen.next())
	print(gen.next())

  1. 関数「test_yield」の戻りの型を表示する。
  2. 関数「test_yield」で得たgenerator変数「gen」に代入する
  3. next()関数を使って変数「gen」の次の項目を表示する
  4. next()関数を使って変数「gen」の次の項目を表示する
  5. next()関数を使って変数「gen」の次の項目を表示する

次の結果のように、関数「test_yield」から返却されたジェネレータ(ここでは変数gen)のメンバ関数である「next」を呼ぶと、次のyield までの処理を実行し、値を返します。もう一度「next」を呼ぶと、次の「yield」で指定される値を返してくれることがわかります。

$ python test.py
<type 'generator'>
10
6
16
4

下のサンプルプログラムのように、関数「test_yield」の中で定義されている「yield」の数以上にnextを呼び出してみましょう。関数「test_yield」の中では、4つの「yield」で指定された処理がありましたが、ここでは5回「next」を呼び出しています。

if __name__ == '__main__':

	print(type(test_yield()))

	gen = test_yield()
	print(gen.next())
	print(gen.next())
	print(gen.next())
	print(gen.next())
	print(gen.next())

  1. 関数「test_yield」の戻りの型を表示する。
  2. 関数「test_yield」で得たgenerator変数「gen」に代入する
  3. next()関数を使って変数「gen」の次の項目を表示する
  4. next()関数を使って変数「gen」の次の項目を表示する
  5. next()関数を使って変数「gen」の次の項目を表示する
  6. next()関数を使って変数「gen」の次の項目を表示する
  7. next()関数を使って変数「gen」の次の項目を表示する

下の実行結果表示のように、「yield」の数以上に「next」を呼び出すとエラーになってしまいます。

$ python test.py
<type 'generator'>
10
6
16
4
Traceback (most recent call last):
  File "test.py", line 23, in <module>
    print(gen.next())
StopIteration