ジェネレータ
前回、PythonのグラフィックスライブラリTurtleで塗りつぶしの注意点として塗りつぶしは軌跡に対して判定されるということを紹介しました。
今回はPythonの基礎として「ジェネレータ」というのを学んでいきます。
というのもTurtleを使っていて、複数の亀さんを同時に動かす(ように見せる)にはジェネレータを使うらしいのですが、これまで使ったことがなかったので、それなら勉強してみようかと。
「ジェネレータ」の前にPythonには「イテレータ」という概念があるそうです。
「イテレータ」とは格納された要素を一つずつ順番に取り出すことができるインターフェースということで、リストやタプル、辞書なんかはイテレータを使って実装されているとのことです。
「ジェネレータ」はそんな「イテレータ」の一種で要素を取り出すごとに処理をして、その値を返すものらしいです。
詳しく学びたい方はこちらのページを含め、他のサイトを調べてみてください。
ジェネレータの作り方
ジェネレータは関数の形で作成していきます。
ただ通常関数で値を返す場合は「return」を使いますが、ジェネレータでは「yield」を使います。
一番簡単に作るとこんな感じ。
def generator():
yield 1
yield 2
yield 3
for gen in generator():
print(gen)
ジェネレータの特徴としてはその関数が呼び出されると「yield」まで処理が進み、その値が返され、処理が停止することです。
つまり上記の例ではgeneretor関数が呼び出された1回目は「1」が返されます。
そして2回目に呼び出された時は「2」、3回目に呼び出された時は「3」が返されます。
「return」では入力値が同じ場合は同じ値が返されますが、「yield」ではこのように他の値を返すことができるというわけです。
ジェネレータの呼び出し方
ジェネレータの呼び出し方としてはfor文で呼び出す方法と「ジェネレータ.__next__()」で呼び出す方法、そして「next(ジェネレータ)」で呼び出す方法があります。
for文で呼び出す方法はこんな感じです。
def generator():
yield 1
yield 2
yield 3
for gen in generator():
print(gen)
実行結果
1
2
3
「ジェネレータ.__next__()」で呼び出す方法はこんな感じです。
def generator():
yield 1
yield 2
yield 3
gen = generator()
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
実行結果
1
2
3
「next(ジェネレータ)」で呼び出す方法はこんな感じです。
def generator():
yield 1
yield 2
yield 3
gen = generator()
print(next(gen))
print(next(gen))
print(next(gen))
実行結果
1
2
3
またもちろんですがジェネレータ関数に引数を設定し、それを内部で処理して返すことも可能です。
def generator(a):
for a_num in range(a):
yield a_num * a_num
gen = generator(3)
print(next(gen,999))
print(next(gen,999))
print(next(gen,999))
print(next(gen,999))
実行結果
0
1
4
999
呼び出し回数がyieldの数を超えた場合
呼び出し回数が関数ないのyieldの数を超えた場合は「StopIteration」のエラーが返されます。
def generator():
yield 1
yield 2
yield 3
gen = generator()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
実行結果
1
2
3
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Cell In[27], line 10
8 print(next(gen))
9 print(next(gen))
---> 10 print(next(gen))
StopIteration:
この際、エラーではなく特定の値を返して欲しい場合は「next(オブジェクト, 値)」というように2つ目の引数にその値を記載します。
def generator():
yield 1
yield 2
yield 3
gen = generator()
print(next(gen, "a"))
print(next(gen, "a"))
print(next(gen, "a"))
print(next(gen, "a"))
実行結果
1
2
3
a
リスト、タプル、辞書への変換
ジェネレータは「list(ジェネレータ)」、「tuple(ジェネレータ)」、「dict(ジェネレータ)」とすることでそれぞれリスト、タプル、辞書へと変換可能です。
ただし辞書へ変換する場合は辞書のキーと要素の2つを返す必要があることに注意してください。
def generator():
yield 1
yield 2
yield 3
print(list(generator()))
実行結果
[1, 2, 3]
def generator():
yield 1
yield 2
yield 3
print(tuple(generator()))
実行結果
(1, 2, 3)
def generator():
yield "a", 1
yield "b", 2
yield "c", 3
print(dict(generator()))
実行結果
{'a': 1, 'b': 2, 'c': 3}
逆にリスト、タプル、辞書からジェネレータを作成する場合は「iter(オブジェクト)」とします。
また辞書の場合はキーのみが返ってくることに注意してください。
list1 = [1, 2, 3]
iter1 = iter(list1)
print(next(iter1))
print(next(iter1))
print(next(iter1))
実行結果
1
2
3
tuple1 = (1, 2, 3)
iter2 = iter(tuple1)
print(next(iter2))
print(next(iter2))
print(next(iter2))
実行結果
1
2
3
dict1 = {'a': 1, 'b': 2, 'c': 3}
iter3= iter(dict1)
print(next(iter3))
print(next(iter3))
print(next(iter3))
実行結果
a
b
c
これでなんとなくジェネレータの使い方が分かってきました。
次回は実際にジェネレータを使ってTurtleを動かしてみましょう。
ではでは今回はこんな感じで。
コメント