Python の itertools
モジュールには、開発を効率化するさまざまな関数が含まれています。その中でも、同じ値を繰り返し返すイテレータを提供する itertools.repeat()
は、意外と知られていない便利な機能です。この記事では、基本的な使い方から実践的な応用例、さらにはパフォーマンスやメモリ効率についても深掘りしていきます!
itertools.repeat() とは?
まずは、基本的な構文を見てみましょう。
import itertools
itertools.repeat(object, times=None)
引数の説明
object
: 繰り返し返される値。times
: 繰り返しの回数(省略可能)。設定しなければ無限に繰り返します。
基本的な使い方
まずは簡単な例から。
import itertools
for value in itertools.repeat("Hello", 3):
print(value)
出力
Hello
Hello
Hello
この例では、"Hello"
が 3 回繰り返して出力されます。もし times
を省略すると、無限に繰り返されるので注意が必要です。
実用例: データ処理に活用する
itertools.repeat()
は、データ処理や関数の引数として利用する場合に特に便利です。
例1: map() と組み合わせて使う
リストの要素をすべて 2 乗したい場合、itertools.repeat()
を使うことで簡潔に書くことができます。
import itertools
numbers = [1, 2, 3, 4, 5]
squared = map(pow, numbers, itertools.repeat(2)) # 各要素を2乗する
print(list(squared))
出力
[1, 4, 9, 16, 25]
解説
itertools.repeat(2)
は 2
を繰り返し返しますが、map()
は numbers
の長さに合わせて処理を行うため、無限に続くわけではありません。
例2: リストを定数で埋める
リストを同じ値で埋める場合、itertools.repeat()
を使うとシンプルです。
import itertools
filled_list = list(itertools.repeat(0, 5))
print(filled_list)
出力
[0, 0, 0, 0, 0]
このように、5 つの 0
で構成されたリストを簡単に作成できます。
repeat() のパフォーマンスを検証してみる
同じ値を繰り返すリストを作成する方法として、リスト内包表記や *
演算子を使うこともできます。それらと比較して、itertools.repeat()
がどれほど効率的か検証してみましょう。
import itertools
import time
n = 10**6
# itertools.repeat
start = time.time()
repeat_list = list(itertools.repeat(0, n))
end = time.time()
print(f"itertools.repeat: {end - start:.6f} 秒")
# List comprehension
start = time.time()
comprehension_list = [0 for _ in range(n)]
end = time.time()
print(f"リスト内包表記: {end - start:.6f} 秒")
# Multiplication operator
start = time.time()
multiplication_list = [0] * n
end = time.time()
print(f"* 演算子: {end - start:.6f} 秒")
出力例
itertools.repeat: 0.042 秒
リスト内包表記: 0.062 秒
* 演算子: 0.035 秒
解説
itertools.repeat()
はメモリ効率が高く、大規模なデータでは特に有利です。*
演算子は速度が速いものの、メモリに負荷がかかる場合があります。
イテレータとリストの違いに注意
itertools.repeat()
はイテレータを返すため、リストと異なりメモリ消費が少なく済みます。ただし、sys.getsizeof()
で計測できるのはイテレータ自体のサイズのみで、生成されるオブジェクトのサイズは含まれません。
メモリ比較の例
import itertools
import sys
iterator = itertools.repeat(0, 10**6)
print(f"Iterator size: {sys.getsizeof(iterator)} bytes")
list_data = [0] * 10**6
print(f"List size: {sys.getsizeof(list_data)} bytes")
出力例
Iterator size: 48 bytes
List size: 8000000 bytes
注意
sys.getsizeof()
はイテレータのオーバーヘッドのみを計測するため、実際のメモリ使用量はさらに異なる可能性があります。
itertools.cycle() との違い
類似した関数に itertools.cycle()
がありますが、こちらはシーケンス全体を無限にループします。対して repeat()
は、同じオブジェクトを繰り返し返します。
例: cycle と repeat の違い
import itertools
print(list(itertools.islice(itertools.repeat(1, 5), 5))) # [1, 1, 1, 1, 1]
print(list(itertools.islice(itertools.cycle([1, 2, 3]), 5))) # [1, 2, 3, 1, 2]
解説
repeat()
は単一の値を繰り返します。cycle()
はシーケンス全体を無限にループします。
まとめ
itertools.repeat()
は、以下のような場面で便利に使えます:
- 同じ値を繰り返し使用したいとき
- メモリ効率を重視したデータ処理
- 関数の引数として定数を繰り返し渡したいとき
ぜひ、日々のプログラミングに取り入れてみてください。シンプルながら強力なツールで、コードの効率がアップします!