ラベル Python技術 の投稿を表示しています。 すべての投稿を表示
ラベル Python技術 の投稿を表示しています。 すべての投稿を表示

2026年6月29日月曜日

Python技術 generator と呼ばれる関数の作り方、機能、特徴、使う場面など具体的に解説してください。

 Pythonの「ジェネレータ(Generator)」は、「必要なときに、必要な分だけデータを生成する」ための特殊な関数です。

大量のデータを扱う際、メモリを節約しながら効率的に処理を行えるのが最大の特徴です。

1. ジェネレータの作り方

ジェネレータを作るには、通常の関数で return の代わりに yield を使います。これだけで、その関数は「ジェネレータ関数」になります。




Python

def count_up(n):
    i = 1
    while i <= n:
        yield# ここで一旦停止し、値を返す
        i += 1

# ジェネレータオブジェクトの作成
gen = count_up(3)

# 値を一つずつ取り出す
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
# print(next(gen))  # これ以上データがないと StopIteration エラーが発生

2. 機能と特徴

ジェネレータの挙動は、通常の関数とは大きく異なります。

  • 状態の保持: yield で値を返した後、関数は終了せずにその場所(状態)を保持したまま待機します。次に next() が呼ばれると、止まった場所から再開します。

  • 遅延評価(Lazy Evaluation): 値が必要になるまで計算を行いません。

  • イテレータとしての性質: next() で値を呼び出せるほか、for 文などでループ処理が可能です。

3. ジェネレータを使うべき理由(メリット)

なぜ通常のリスト(配列)ではなく、ジェネレータを使うのでしょうか。それはメモリ効率にあります。

  • リストの場合: 100万個の数値をリストで作ると、100万個分のデータを一度にメモリ上に確保します。

  • ジェネレータの場合: 常にメモリ上にあるのは「今の1個」だけです。どれだけ大きなデータを扱っても、メモリ使用量が一定(極小)に保たれます。

4. 使うべき場面

実務で特に力を発揮するのは以下のようなシーンです。

  • 巨大なログファイルの読み込み:
    数GBあるログファイルを一度に読み込むとメモリがパンクします。ジェネレータなら「1行ずつ読んで処理する」ということが簡単に書けます。

  • 無限のストリーム処理:
    センサーからのデータなど、終わりがわからない連続的なデータを扱う際に適しています。

  • パイプライン処理:
    「データを加工する」処理を複数のジェネレータでつなぎ合わせると、効率的なデータ処理パイプラインを構築できます。

5. おまけ:ジェネレータ式

リスト内包表記のように、一行でジェネレータを書くこともできます([] の代わりに () を使います)。




Python

# リスト内包表記(メモリを食う)
data_list = [x * 2 for x in range(1000000)]

# ジェネレータ式(メモリを食わない)
data_gen = (x * 2 for x in range(1000000))

まとめ:

  • yield を見たらジェネレータだと判断する。

  • 大量のデータを扱うときは、リストよりジェネレータ。

  • 「メモリをケチりたいとき」が使いどき。

この仕組みを理解すると、データ解析やWebスクレイピングなど、大規模なデータを扱うプログラムが格段に書けるようになりますよ。


Python技術 デコレータで関数に機能を追加する方法を具体的にわかりやすく解説してください。

 デコレータは、既存の関数のソースコードを直接書き換えることなく、「関数の実行前後」に新しい機能を追加・拡張するための強力な仕組みです。

一言でいうと、「関数をラップ(包む)して、中身を付け足すもの」とイメージしてください。

1. デコレータの基本構造

デコレータは、「関数を引数にとり、新しい関数(wrapper)を返す関数」です。




Python

def my_decorator(func):
    def wrapper():
        print("--- 実行前の処理 ---")
        func()  # 元の関数を実行
        print("--- 実行後の処理 ---")
    return wrapper

@my_decorator
def say_hello():
    print("こんにちは!")

say_hello()

実行結果:




--- 実行前の処理 ---
こんにちは!
--- 実行後の処理 ---

  • @my_decorator という記述が「この関数をデコレータで包む」という合図(糖衣構文)です。

  • say_hello 関数は、実際には my_decorator が返した wrapper に置き換わっています。

2. なぜデコレータを使うのか?

「関数の中身を書き換えればいいのでは?」と思うかもしれませんが、デコレータには以下のメリットがあります。

  1. DRY原則(同じコードを書かない): 複数の関数で「ログ出力」「実行時間の計測」「ログインチェック」などの共通処理が必要な場合、デコレータ一つで対応できます。

  2. 既存コードを汚さない: 元の関数の機能を変更せずに、外側から機能を追加できるため、バグを混入させにくいです。

3. 【実践】実行時間を計測するデコレータ

実際の開発でよく使われる、関数の実行時間を計測する例です。




Python

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):  # 引数を受け取れるようにする
        start = time.time()
        result = func(*args, **kwargs)  # 元の関数の戻り値を保持
        end = time.time()
        print(f"実行時間: {end - start:.4f}秒")
        return result  # 戻り値を返す
    return wrapper

@timer_decorator
def heavy_task(n):
    time.sleep(n)
    return "完了"

print(heavy_task(1))

  • *args, kwargs を使うことで、どんな引数を持つ関数にも対応できるようになります。

  • return result を書くことで、元の関数の戻り値をそのまま呼び出し元に渡せます。

4. まとめ:デコレータ習得のステップ

  1. まずは「ラップするだけ」の関数を作る: 上記の wrapper パターンを真似して書いてみる。

  2. 引数と戻り値に対応する: *args と return を意識する。

  3. 既存の便利なデコレータを使う: Python標準の @staticmethod や @classmethod、あるいはWebフレームワーク(Flaskなど)でよく使われる @app.route() などに触れてみる。

デコレータを使えるようになると、「関数を部品として扱う」感覚が身につき、コードが劇的に洗練されますよ。