Python で無限シーケンスを作る

ジェネレータを使うと、終わりのない「無限シーケンス」を作ることができます。すべての要素をメモリに保持する必要がないため、理論上は永遠に続くシーケンスも表現できます。

基本的な無限シーケンス

永遠にカウントアップするジェネレータを作ってみましょう。

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 で取り出す量を制限してください。