
Python Cookbook [Creating New Iteration Patterns with Generators : ジェネレーターを利用した独自イテレーションパターンの実装] 投稿一覧へ戻る
Published 2020年5月7日19:19 by T.Tsuyoshi
Problem:
range() や reversed() といった組み込み関数とは異なるイテレーションパターンを実装したい。
Solution:
generator 関数を利用して実装します。
例えば、ある範囲内、あるステップ数で浮動小数点数を生成したいなら次のようになるでしょう。
def float_range(start, stop, step):
x = start
while x < stop:
yield x
x += step
x = start
while x < stop:
yield x
x += step
こういった関数を利用するには、for ステートメントであるとか、sum() や list() といった内部でイテラブルを利用する他の関数等と一緒に使用します。
for n in float_range(5, 10, 0.5):
print(n)
list(float_range(0, 1, 0.125))
print(n)
# 5
# 5.5
# 6.0
# 6.5
# 7.0
# 7.5
# 8.0
# 8.5
# 9.0
# 9.5
list(float_range(0, 1, 0.125))
# [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875]
関数内に yield ステートメントが含まれていれば、その関数は generator 関数になります。
通常の関数とは異なり、generator 関数はイテレーション操作に反応して機能します。
以下のスニペットは、generator 関数の基本的なメカニズムを理解するためのものです。
python インタラクティブシェルで実行します。
>>> def countdown(n):
... print('{} からカウントダウンを開始します'.format(n))
... while n > 0:
... yield n
... n -= 1
... print('発射!!!!')
>>> c = countdown(3)
>>> c
... print('{} からカウントダウンを開始します'.format(n))
... while n > 0:
... yield n
... n -= 1
... print('発射!!!!')
>>> c = countdown(3)
>>> c
# <generator object countdown at 0x0000000004D34F48>
↑ generator をインスタンス化しただけでは何もプリントアウトされません。
これは、イテレーション操作が一切行われていないためです。
>>> next(c)
3 からカウントダウンを開始します
3
3 からカウントダウンを開始します
3
↑ 最初の yield が実行され値が渡されてきます
>>> next(c)
2
2
↑ 次の yield の実行
>>> next(c)
1
1
↑ その次の yield の実行
>>> next(c)
発射!!!!
Traceback (most recent call last):
File "", line 1, in
StopIteration
発射!!!!
Traceback (most recent call last):
File "
StopIteration
↑ そのまた次の yield の実行。ここで、イテレーション最後だよ、の例外が発生します
ここで分かることは、generator 関数はイテレーション内で実行される "next" 操作に反応して実行される、ということです。
1回 generator 関数が値を返すと、イテレーションはその場所でストップします。
イテレーション操作に通常利用される for ステートメント等では、こういったことが水面下で自動的に行われているわけです。
こちらの投稿にも興味があるかもしれません...
- Python Cookbook [Implementing the Iterator Protocol : イテレータープロトコルの実装]
- 【 Effective Python, 2nd Edition 】throw() メソッドを利用したジェネレータ ( generator ) 内部での状態遷移はなるだけ避けましょう。ネストが深くなってコードの読解性が落ちちゃいますよ!
- Python Cookbook [Manually Consuming an Iterator : 手作業によるイテレーション操作]
- 【Python 雑談・雑学 + coding challenge】iterator protocol の実装 --- __iter__ 特殊関数は何を返すべき? イテレータオブジェクト ( iterator object ) なら何でも、そう、generator expression でもOKです!
2 comments
Comment 2 by Manager 2020年5月21日20:18
Hello, Grady.
I really appreciate your comment, thank you.
Your comment gives me an courage to keep posting.
Comment 1 by Grady 2020年5月21日15:13
Hola! I've been reading your web site for a while now and finally
got the courage to go ahead and give you a shout out from
Porter Tx! Just wanted to mention keep up the good
job! You've made some decent points there. I checked on the web for more info
about the issue and found most people will go along with your views on this web
site. I have been surfing online more than 4 hours today,
yet I never found any interesting article like yours.
It’s pretty worth enough for me. In my opinion, if all web owners and bloggers made good content as
you did, the internet will be much more useful than ever before.
http://foxnews.org