Python

【Python】ジェネレータの使い方

この記事では、Pythonのジェネレータの使い方を解説します。

ジェネレータはイテレータを簡単に作成するための機能です。リストやタプルなどを使わなくても複数の値を返す関数を定義することができます。

イテレータについては以下の記事を参考にしてください。

【Python】イテラブルオブジェクトとイテレータとは?この記事では、Pythonのイテラブルオブジェクトとイテレータについて解説します。 よくリストなどやfor文あたりで見かけますが、一体...

それでは、ジェネレータの使い方を見ていきましょう!

ジェネレータの使い方

ジェネレータはyield文を使って定義します。

def 関数名():
    yield 戻り値

yieldは同時にいくつでも定義することもできます。

def 関数名():
    yield 戻り値1
    yield 戻り値2
    yield 戻り値3
POINT
  • ジェネレータ関数内ではreturnは使えません
  • yield文が処理されても関数は終了しません

サンプル

以下のコードでは、yieldを使って複数の値を返しています。

def func():
    yield 1
    yield 'Hello'
    yield [1, 2, 3]


result = func()
print(result)
print(list(result))

実行結果

<generator object func at 0x1039403d0>
[1, 'Hello', [1, 2, 3]]

ジェネレータオブジェクト

ジェネレータ関数を実行するとジェネレータオブジェクト(ジェネレータイテレータとも呼ぶ)が返されます。

<generator object 関数名 at 0x10bef73d0>

ジェネレータオブジェクトはfor文で要素にアクセスしたり、

for val in ジェネレータオブジェクト:
    print(val)

# yieldで返した値1
# yieldで返した値2
# yieldで返した値3
・
・
・

リストやタプルに変換したりできます。

list(ジェネレータオブジェクト)

サンプル

以下のコードは、渡された文字列を1文字ずつ文字コードにして返します。

def ords(string: str):
    for char in string:
        # yieldで文字コードを返す
        yield ord(char)


for o in ords('abc'):
    print(o)

# リストに変換
print(list(Ords('abc')))

実行結果

97
98
99
[97, 98, 99]

ジェネレータの仕組み

ジェネレータは以下のように処理されています。

  1. yield文で値を返した時に処理を中断して、その場所を記憶する
  2. 新たに値を要求されたら記憶した場所から処理を再開する

これを繰り返すことでジェネレータは複数の値を返しています。

サンプル

以下の例を見てください。next()で要素を要求されるたび、関数内のprint()によって値が出力されているのがわかります。

def generator():
    print('start')
    print('yield 1')
    yield 1
    print('yield 2')
    yield 2
    print('yield 3')
    yield 3
    print('end')


g = generator()

# next()で次の要素を要求できる
print('next 1')
print(next(g))
print('next 2')
print(next(g))
print('next 3')
print(next(g))
print('next 4')
print(next(g))

実行結果

next 1
start
yield 1
1
next 2
yield 2
2
next 3
yield 3
3
next 4
end
Traceback (most recent call last):
  File "main.py", line 22, in <module>
    print(next(g))
StopIteration

このように、ジェネレータは値を求められるたびに演算して要素を返しています。通常の関数と違い演算コストを分散させることができます。

注意:前回記憶した場所から再開する

ジェネレータオブジェクトが呼び出された場合、記憶した場所から処理を再開します。

例えば以下のような場合も同様です。

def func():
    yield 1
    yield 2
    yield 3

g = func()

print('1度目のループ')
for v in g:
    print(v)

print('2度目のループ')
for v in g:
    print(v)

実行結果

1度目のループ
1
2
3
2度目のループ

1度目のループで最後の値まで処理したので2度目のループでは何も出力されません。

何度も参照する場合はリストやタプルを使いましょう!

ジェネレータ式

単純なジェネレータならば、さらに簡潔に式として記述することができます。

ジェネレータ式は内包表現と同じ書き方をします。

(戻り値 for 変数名 in イテラブルオブジェクト)
[] ではなく () を使う点に注意してください

サンプル

先ほどのサンプルで作成したジェネレータ関数をジェネレータ式で書き換えてみましょう!

for n in (ord(char) for char in 'abc'):
    print(n)

実行結果

97
98
99

for文と合わせて2行で実装できてしまいました。

このように単純なジェネレータはジェネレータ式を使って実装しましょう!

まとめ

この記事では、Pythonのジェネレータの使い方を解説しました。

ジェネレータを使う機会は多くないですが、複数の値を返したいけどリストやタプルなどを使いたくない場合は実装を検討してみてはいかがでしょうか?

今回のおさらい

今回の内容をおさらいしましょう!

# ジェネレータ
def 関数名():
    yield 戻り値1
    yield 戻り値2
    yield 戻り値3

# ジェネレータ式
(戻り値 for 変数名 in イテラブルオブジェクト)

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ

最短3か月でエンジニア転職「DMM WEBCAMP COMMIT」
なんと転職成功率98%!
今なら3日以内のカウンセリング枠を予約&参加で「1,000円分のAmazonギフト券」をプレゼント!