Python - ジェネレーター: 初心者向けの優しくなった入門
こんにちは、Pythonプログラマー志願者の皆さん!今日は、Pythonのジェネレーターの世界について素晴らしい旅に出かけます。以前に聞いたことがないとしても心配しないでください —— まず最初から始めて、少しずつ進んでいきます。このチュートリアルの最後には、プロのようにジェネレーターを作成できるようになります!
Pythonのジェネレーターとは?
本を読んでいるときを想像してください。一度にすべてのページをコピーする(それはたくさんの紙を無駄にするのです!)よりも、一ページずつ読んでいくのが良いでしょう。それがPythonのジェネレーターがどのように動くかの良い例です!
ジェネレーターは、一度にすべての値を計算してメモリに保存するのではなく、時間とともに一連の値を生成する特別な関数です。それは、必要なときに値を生成する魔法の工場のようなものです。
なぜジェネレーターを使うのか?
- メモリ効率: ジェネレーターはメモリに優しいです。すべての値を一度にメモリに保存する必要がありません。
- パフォーマンス: 大規模なデータセットを扱う際に、コードのパフォーマンスを向上させることができます。
- シンプルさ: ジェネレーターを使うことで、コードがよりクリーンで読みやすくなります。
それでは、どのように動くのかを見ていきましょう!
ジェネレーターの作成
Pythonでジェネレーターを作成するには、主に2つの方法があります:
- ジェネレーター関数を使用する
- ジェネレーター式を使用する
ジェネレーター関数
ジェネレーター関数は、通常の関数とほぼ同じように見えますが、return
キーワードの代わりにyield
を使用します。以下に簡単な例を示します:
def count_up_to(n):
i = 1
while i <= n:
yield i
i += 1
# ジェネレーターを使用する
for number in count_up_to(5):
print(number)
出力:
1
2
3
4
5
この例では、count_up_to
はジェネレーター関数です。それは値を生成するたびに、実行を一時停止し、状態を覚えます。次回呼び出されたときに、停止した場所から再開します。
ジェネレーター式
ジェネレーター式はリスト内包表記のように見えますが、角括弧の代わりに括弧を使用します。これはジェネレーターを作成するためのコンパクトな方法です。以下に例を示します:
# ジェネレーター式
squares = (x**2 for x in range(5))
# ジェネレーターを使用する
for square in squares:
print(square)
出力:
0
1
4
9
16
このジェネレーター式は、すべての値を一度にメモリに保存することなく、実行時に一連の平方数を生成します。
ジェネレーター内の例外処理
ジェネレーターは例外を処理することもできます。これはかなりすごいです!以下に例を示します:
def div_generator(a, b):
try:
result = a / b
yield result
except ZeroDivisionError:
yield "0で割ることはできません!"
# ジェネレーターを使用する
g = div_generator(10, 2)
print(next(g)) # 出力: 5.0
g = div_generator(10, 0)
print(next(g)) # 出力: 0で割ることはできません!
この例では、ジェネレーターがゼロ除算のケースを優しく処理しています。
通常関数とジェネレーター関数の比較
通常の関数とジェネレーター関数の違いを見てみましょう:
# 通常の関数
def get_squares(n):
squares = []
for i in range(n):
squares.append(i**2)
return squares
# ジェネレーター関数
def gen_squares(n):
for i in range(n):
yield i**2
# 通常の関数を使用する
print(get_squares(5)) # 出力: [0, 1, 4, 9, 16]
# ジェネレーター関数を使用する
for square in gen_squares(5):
print(square) # 各平方数を新しい行に出力
主な違いは以下の通りです:
- メモリ使用量: 通常の関数は一度にすべての値を作成して保存する一方で、ジェネレーターは一度に一つの値を生成します。
- 構文: 通常の関数は
return
を使用し、ジェネレーターはyield
を使用します。 - 反復: ジェネレーターは直接反復することができますが、通常の関数の結果はまず変数に保存する必要があります。
非同期ジェネレーター
Python 3.6で導入された非同期ジェネレーターは、通常のジェネレーターのようですが、非同期プログラミング用です。async def
とyield
を使用します:
import asyncio
async def async_gen():
for i in range(3):
await asyncio.sleep(1)
yield i
async def main():
async for item in async_gen():
print(item)
asyncio.run(main())
この例では、非同期操作が時間とともに値を生成することをシミュレートしています。
ジェネレーターのメソッド
ジェネレーターには、特に便利な特殊メソッドがいくつかあります。以下に最も一般的なものを表に示します:
メソッド | 説明 |
---|---|
next() |
ジェネレーターから次のアイテムを取得する |
send() |
ジェネレーターに値を送る |
throw() |
ジェネレーター内で例外を発生させる |
close() |
ジェネレーターを閉じる |
以下にsend()
を使用する簡単な例を示します:
def echo_generator():
while True:
received = yield
print(f"受信: {received}")
g = echo_generator()
next(g) # ジェネレーターを初期化
g.send("こんにちは") # 出力: 受信: こんにちは
g.send("世界") # 出力: 受信: 世界
それでは、これで終わりです!Pythonのジェネレーターの素晴らしい世界に踏み込んだ最初の一歩をお楽しみください。覚えることは、練習が実践になるので、これらの概念について実験することを恐れずにやってください。知らずにして、Pythonプログラムでさまざまな興味深い問題を解決するためにジェネレーターを使用するようになるでしょう。楽しいコーディングを!
Credits: Image by storyset