ジェネレータを使うと、終わりのない「無限シーケンス」を作ることができます。すべての要素をメモリに保持する必要がないため、理論上は永遠に続くシーケンスも表現できます。
基本的な無限シーケンス
永遠にカウントアップするジェネレータを作ってみましょう。
def count_forever(start=0): n = start while True: yield n n += 1 counter = count_forever() print(next(counter)) # 0 print(next(counter)) # 1 print(next(counter)) # 2 # 呼び続ける限り永遠に続く
無限シーケンスの活用
無限シーケンスは、必要な数だけ取り出して使います。
from itertools import islice def count_forever(start=0): n = start while True: yield n n += 1 # 最初の5個だけ取り出す first_five = list(islice(count_forever(), 5)) print(first_five) # [0, 1, 2, 3, 4] # 10番目から15番目まで取り出す some_numbers = list(islice(count_forever(), 10, 15)) print(some_numbers) # [10, 11, 12, 13, 14]
実用的な無限シーケンス
いくつかの実用的な例を見てみましょう。
# フィボナッチ数列(無限) def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b # 最初の10個 from itertools import islice print(list(islice(fibonacci(), 10))) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# 素数列(無限) def primes(): def is_prime(n): if n < 2: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True n = 2 while True: if is_prime(n): yield n n += 1 print(list(islice(primes(), 10))) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
サイクルシーケンス
要素を無限に繰り返すシーケンスも作れます。
def cycle(iterable): items = list(iterable) while True: for item in items: yield item colors = cycle(["赤", "青", "緑"]) for i, color in enumerate(colors): if i >= 7: break print(color, end=" ") # 赤 青 緑 赤 青 緑 赤
条件付きで停止する
無限シーケンスでも、条件を満たしたら停止できます。
def count_forever(): n = 0 while True: yield n n += 1 # 条件を満たすまで取り出す for n in count_forever(): if n > 100: break if n % 15 == 0: print(n, end=" ") # 0 15 30 45 60 75 90
itertools の無限イテレータ
標準ライブラリの itertools には、便利な無限イテレータが用意されています。
from itertools import count, cycle, repeat # count: 無限カウント for n in count(10, 2): # 10から2ずつ if n > 20: break print(n, end=" ") # 10 12 14 16 18 20 # repeat: 同じ値を繰り返す for x in repeat("A", 3): # 3回だけ print(x, end=" ") # A A A
無限シーケンスは、ストリームデータの処理、シミュレーション、数学的なシーケンスの表現などに便利です。ただし、list() で変換しようとすると永遠に終わらないので、必ず islice() や条件付きの break で取り出す量を制限してください。