【Python】ジェネレータを利用してイテレータを取得する
Pythonのジェネレータを利用してイテレータを取得する
ジェネレータとは?
ジェネレータ(generator)は、Pythonのイテレータ(iterator)を簡単に作成できる特殊な関数です。通常の関数とは異なり、return
の代わりに yield
を使います。
ジェネレータを利用すると、要素を逐次的に生成できるため、メモリ効率が向上し、大量のデータを扱う際に有用です。
基本的な使い方
まずは基本的なジェネレータの定義と使用方法を見てみましょう。
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # StopIteration エラー
yield
を使うことで、関数が途中で停止し、次に next()
を呼び出すと、停止した位置から再開します。
通常の関数との違い
通常の関数とジェネレータの違いを比較します。
通常の関数
def normal_function():
return [1, 2, 3]
print(normal_function()) # [1, 2, 3]
ジェネレータ
def generator_function():
yield 1
yield 2
yield 3
gen = generator_function()
print(list(gen)) # [1, 2, 3]
通常の関数は全てのデータを一度に返しますが、ジェネレータは1つずつ値を返します。
実用的なジェネレータの例
ファイルの行を1行ずつ読む
def read_large_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
yield line.strip()
for line in read_large_file("large_text.txt"):
print(line)
無限に値を生成する
def infinite_counter():
num = 0
while True:
yield num
num += 1
counter = infinite_counter()
print(next(counter)) # 0
print(next(counter)) # 1
print(next(counter)) # 2
パフォーマンスの利点
- ジェネレータは一度に1つの値しかメモリに保持しないため、メモリ使用量が削減される。
- 大きなリストを作成せずにデータを逐次処理できるため、処理速度が向上する。
応用的なジェネレータの使い方
ジェネレータでフィルタリング
def even_numbers(n):
for num in range(n):
if num % 2 == 0:
yield num
print(list(even_numbers(10))) # [0, 2, 4, 6, 8]
ジェネレータを使ったパイプライン処理
def numbers():
for i in range(10):
yield i
def square(numbers):
for num in numbers:
yield num ** 2
def even_filter(numbers):
for num in numbers:
if num % 2 == 0:
yield num
pipeline = even_filter(square(numbers()))
print(list(pipeline)) # [0, 4, 16, 36, 64]
ジェネレータ式
リスト内包表記に似た形でジェネレータを作成できます。
gen_exp = (x**2 for x in range(10))
print(next(gen_exp)) # 0
print(next(gen_exp)) # 1
リスト内包表記 [x**2 for x in range(10)]
と違い、ジェネレータ式は必要な時に値を生成します。
まとめ
- ジェネレータは
yield
を使用し、イテレータを簡単に作れる。 - メモリ効率が良く、大量のデータ処理に適している。
- ファイル処理や無限ループなど、実用的な用途が多い。