【Pythonを使いこなす100日】24日目:Pythonのイテレータ、ジェネレータ、デコレータの詳しい解説と例

 目次

 コラムガイド 

1 イテレータ、ジェネレータ、デコレータの概要

1.1 概要

1.2 応用シナリオ

2 構文と例

2.1 イテレータ

2.2 ジェネレーター

2.3 デコレータ

3 包括的な応用例


コラムガイド 

コラム購読アドレス:https://blog.csdn.net/qq_35831906/category_12375510.html


1 イテレータ、ジェネレータ、デコレータの概要

1.1 概要

  1. イテレータ (イテレータ): イテレータは、反復プロトコルを実装し、コンテナ内の要素を横断できるオブジェクトです。イテレータには2 つのメソッド__iter__()と が含まれている必要があります。メソッドはイテレータ オブジェクト自体を返し、メソッドはコンテナ内の次の要素を返します。コンテナ内の要素が走査されると、例外が発生する必要があります__next__()__iter__()__next__()__next__()StopIteration

  2. ジェネレーター: ジェネレーターは、イテレーターをより簡潔に定義できる特別な種類のイテレーターです。ジェネレーターはyieldキーワードを使用して、return結果を返す代わりに次の値を生成します。ジェネレーター関数はyield呼び出されるたびに一時停止し、中断した次の反復で実行を再開します。このような機能により、ジェネレーター機能がよりコンパクトかつ効率的になります。

  3. デコレータ: デコレータは、他の関数の動作を変更するために使用できる高次関数です。デコレーターは関数を入力として受け取り、通常は元の関数をラップして新しい関数を返します。これにより、元の関数コードを変更せずに機能を追加できます。デコレータを使用すると、ログ記録、権限の検証、パフォーマンス分析など、関数の実行の前後に追加のロジックを追加できます。

        これらの概念は Python において非常に重要であり、データの操作、コードの最適化、コードの再利用を実現する多くの便利な方法を提供します。イテレーターとジェネレーターにより、大量のデータの処理がより効率的になり、デコレーターによりコードがよりモジュール化され、保守が容易になります。これらの概念を賢く適用することで、よりエレガントで強力な Python コードを作成できます。

1.2 応用シナリオ

        イテレータ、ジェネレータ、デコレータは、さまざまなプログラミング シナリオで広く使用されている Python プログラミング ツールです。以下は、それらの一般的なプログラミング シナリオです。

  1. イテレータのプログラミング シナリオ:

    • データセットの走査: イテレータを使用すると、データセット全体を一度にメモリにロードするのではなく、オンデマンドでデータを 1 つずつフェッチするため、大規模なデータセットを走査するときにメモリを節約できます。
    • ファイル処理: 大きなファイルの場合は、ファイル全体を一度にメモリに読み込むことなく、反復子を使用してデータを 1 行ずつ読み取って処理します。
    • カスタム コンテナ: イテレータ プロトコルを実装すると、ツリーやグラフなどのカスタム コンテナ オブジェクトを作成できるため、Python の for ループを使用してコンテナ内の要素を走査できるようになります。
  2. ジェネレーターのプログラミング シナリオ:

    • 大規模なデータセットの処理: ジェネレーターはオンデマンドでデータを生成し、すべてのデータを一度にメモリにロードする必要がないため、大規模なデータセットを操作するのに最適です。
    • 無限シーケンス: ジェネレーターは、フィボナッチ数列、素数シーケンスなど、無制限の長さのシーケンスを生成できます。
    • 遅延計算: ジェネレーターを使用すると、必要な場合にのみデータを生成する遅延計算が可能になり、場合によってはパフォーマンスが向上します。
  3. デコレータのプログラミング シナリオ:

    • ロギング: デコレータを使用すると、関数呼び出し情報、パラメータ、および実行時間を記録するロギング機能を関数に追加できます。
    • パフォーマンス分析: デコレータを通じて、パフォーマンス分析と最適化のために関数の実行時間を測定できます。
    • 権限の検証: デコレーターを使用して関数の権限検証を実行し、特定の権限を持つユーザーのみが関数を実行できるようにすることができます。
    • 結果のキャッシュ: デコレーターを使用して関数の結果をキャッシュし、計算の繰り返しを回避し、関数の実行効率を向上させることができます。

包括的なアプリケーション シナリオ:

  • ジェネレーターを使用して大規模なデータセットを処理し、データ処理のロギングとパフォーマンスのためにデコレーターと組み合わせます。
  • イテレータを使用して大きなファイルを走査し、デコレータを組み合わせてアクセス許可の検証を実装し、ファイル処理結果をキャッシュします。
  • ジェネレーターを使用して、フィボナッチ数の生成などの無限シーケンスを生成し、デコレーターを組み合わせてシーケンスの計算時間と結果を記録します。

        概要: イテレータ、ジェネレータ、デコレータはすべて、Python プログラミングにおける幅広いアプリケーション シナリオを持っています。特に大規模なデータセットや複雑なタスクを扱う場合に、コードがより効率的、柔軟で、保守しやすくなります。


2 構文と例

2.1 イテレータ

        Python では、イテレータ (Iterators) はコンテナ内の要素を走査するためのメカニズムです。これは、コレクションの内部構造を知らなくても、コレクション内の各要素にアクセスするためのシンプルかつ統一された方法を提供します。イテレータは、データ セット全体を一度にメモリにロードする必要がなく、オンデマンドでデータを 1 つずつフェッチするため、メモリを節約し、パフォーマンスを向上させることができるため、大規模なデータ セットを扱う場合に非常に役立ちます

        リスト、タプル、辞書、セットなど、Python の多くの組み込みデータ型は反復をサポートしています。イテレータの中心的な考え方は、__iter__()およびメソッドを介した__next__()トラバーサルを実装することです。を呼び出すとiter(iterable)イテレータ オブジェクトが返され、next(iterator)すべての要素が走査されるまで を使用してコンテナ内の次の要素を取得できます。すべての要素が走査された時点でStopIteration例外がスローされます。

簡単なイテレータの例を次に示します。

class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value

# 使用自定义迭代器遍历列表
my_list = [1, 2, 3, 4, 5]
my_iterator = MyIterator(my_list)
for item in my_iterator:
    print(item)

出力:

1
2
3
4
5

MyIterator上の例では、という反復子クラスを定義し、その中に__iter__()メソッドとメソッドを実装しました。__next__()次に、カスタム iterator を使用してリストを反復処理しますmy_list

Python には組み込み関数iter()とが用意されているnext()ため、実際のプログラミングではイテレータ クラスを自分で定義する必要はほとんどないことに注意してください。iter()反復可能なオブジェクトは、と を使用して直接next()反復できます。

my_list = [1, 2, 3, 4, 5]
my_iterator = iter(my_list)
while True:
    try:
        item = next(my_iterator)
        print(item)
    except StopIteration:
        break

出力は以前と同じです

1
2
3
4
5

iter()ここでは、 and関数を使用して next()リストを手動で走査し、StopIteration例外が発生したときに走査を停止します。

概要: イテレータは Python で非常に強力で一般的に使用される機能であり、データの走査をシンプルかつ効率的にします。カスタム イテレータ クラスを使用する場合でも、組み込み関数iter()next()関数を使用する場合でも、イテレータはデータセットを操作するときに非常に便利です。


2.2 ジェネレーター

Python では、ジェネレーターは、キーワードを使用して結果を返すyield代わりに値を生成する        特別なタイプのイテレーターです。returnジェネレーター関数の実行はyield呼び出しごとに一時停止され、中断された次の反復で再開されます。この機能により、ジェネレーター関数がよりコンパクト、効率的、メモリ効率が向上します。

        ジェネレーターの利点は、すべてのデータを一度にメモリーにロードする必要がなく、オンデマンドでデータを生成できることです。これは、メモリ使用量を削減し、プログラムのパフォーマンスを向上させるため、大量のデータを処理する場合に非常に役立ちます。

簡単なジェネレーターの例を次に示します。

def countdown(n):
    while n > 0:
        yield n
        n -= 1

# 使用生成器遍历倒计时
for i in countdown(5):
    print(i)

出力

5
4
3
2
1

         上の例では、countdownというジェネレーター関数を定義しました。各ループでキーワードを使用してyieldカウントダウン値を生成し、次の反復で中断したところから実行が続行されます。したがって、各反復ではカウントダウン値が出力されます。

        ジェネレーター関数は値を返すのではなく、反復子を生成することに注意してください。ジェネレーター関数を呼び出すことでジェネレーター オブジェクトを取得し、それを使用して反復処理を行うことができます。すべての値が生成されると、ジェネレーターは例外をスローしますStopIteration

        Python では、 によるジェネレータの定義に加えてyield、ジェネレータ式を使用してジェネレータを迅速に作成することもサポートしています。ジェネレータ式はリスト内包表記に似ていますが、角括弧の代わりに括弧を使用します。

例:

# 使用生成器表达式生成一个包含 1 到 5 的生成器
my_generator = (x for x in range(1, 6))

# 遍历生成器并输出值
for item in my_generator:
    print(item)

出力

1
2
3
4
5

 ジェネレーターは、Python の強力で柔軟なツールです。yieldキーワードを使用してジェネレーター関数またはジェネレーター式を定義すると、大規模なデータ セットを扱うときにメモリを節約し、パフォーマンスを向上させ、コードをより簡潔にすることができます。


2.3 デコレータ

        デコレータは Python の高度な機能で、元の関数コードを変更せずに関数に機能や動作を追加できるようになります。デコレーターは本質的に、別の関数を引数として受け取り、新しい関数を返す関数です。このようにして、関数の呼び出し前、呼び出し後、または関数の実行中に、いくつかの共通ロジックを挿入できます。

        デコレータ構文では@、デコレータをターゲット関数に適用する前に、この表記法が使用されます。

簡単な例を見てみましょう。

# 定义一个简单的修饰器函数
def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

# 使用修饰器来装饰函数
@my_decorator
def say_hello():
    print("Hello!")

# 调用被装饰的函数
say_hello()

出力:

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

 上の例では、関数を引数としてmy_decorator受け取り、新しい関数を返す というデコレータ関数を定義しました関数内に、ターゲット関数の呼び出しの前後に情報を出力する追加ロジックを追加します。funcwrapperwrapperfunc

次に、@my_decorator構文を使用してmy_decoratorデコレーターを関数に適用しますsay_hello。これにより、次のことが行われます。

say_hello = my_decorator(say_hello)

このようにして、say_hello()関数を呼び出すと、実際には変更されたwrapper関数が呼び出され、「Hello!」の出力の前後に追加のロジックが実行されます。

上記の例に加えて、デコレータはパラメータを受け取ることもできるため、より柔軟になります。例えば:

def repeat(num_times):
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return my_decorator

@repeat(num_times=3)
def say_hello(name):
    print(f"Hello, {name}!")

say_hello("John")

 出力:

Hello, John!
Hello, John!
Hello, John!

repeatこの例では、関数を実行する回数を指定する        パラメーターを使用してデコレーターを定義します。@repeat(num_times=3)この構文を使用して、repeatデコレーターをsay_hello関数に適用し、関数が 3 回実行されるように指定します。

        概要: デコレーターは、コードをよりモジュール化して読みやすくし、元の関数コードを変更せずに共通ロジックを追加できる Python の強力で柔軟なプログラミング ツールです。デコレータを使用すると、ロギング、パフォーマンス分析、権限検証などの一般的な機能を簡単に実装できるため、コードがより洗練され、保守しやすくなります。


3 包括的な応用例

        多数の整数を含むリストがあり、その中の各整数を 2 乗し、関数の実行時間を含む各操作の前後のログを記録する必要があるとします。

以下の機能を含むプログラムを実装する必要があります。

  1. square_generator(data)整数のリストをdata引数として受け取り、ジェネレーターを返すジェネレーター関数を定義します。ジェネレーターは、リスト内の各整数の二乗値を 1 つずつ生成します。
  2. log_decorator(func)関数をfunc引数として受け取り、新しい関数を返すデコレーター関数を定義しますwrapperwrapper関数内ではfunc関数の実行時間を記録し、実行時間ログを出力します。
  3. デコレーターlog_decoratorをジェネレーター関数に適用してsquare_generator、新しい装飾されたジェネレーター関数を作成しますlog_square_generator
  4. 多数の整数を含むリストを作成しdata_list、装飾されたジェネレーター関数を呼び出してlog_square_generator(data_list)、ランタイムのログ出力を監視します。

最終的に、プログラムは大量のデータを処理し、実行時間を自動的に記録できるため、コードがより効率的で保守しやすくなります。

コードは以下のように表示されます:

import time

# 生成器函数:平方生成器
def square_generator(data):
    for item in data:
        yield item ** 2

# 修饰器函数:日志记录
def log_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} executed in {end_time - start_time:.6f} seconds.")
        return result
    return wrapper

# 经过修饰的生成器函数:带有日志记录的平方生成器
@log_decorator
def log_square_generator(data):
    for item in data:
        yield item ** 2

# 创建一个大型数据集的列表
data_list = list(range(1, 1000000001))

# 使用经过修饰的生成器处理数据,并观察日志输出
for square in log_square_generator(data_list):
    pass

出力は次のとおりです。

       上記の場合、最初に、square_generatorリスト内の各要素の 2 乗を返すジェネレーター関数を定義しました。次に、log_decorator関数の実行時間とパラメーターを記録するデコレーター関数を定義します。

        次に、デコレータを に適用し、評価の前後にログを記録するsquare_generator新しいデコレータ ジェネレータ関数を作成します。log_square_generator

     最後に、大規模なデータセットのリストを作成し、装飾されたジェネレーター関数を使用してlog_square_generatorデータを処理し、ログ出力を観察します。コードを実行すると、ジェネレーターの経過時間が記録されることがわかります。

        この完全な例では、イテレーター、ジェネレーター、デコレーターを活用して大規模なデータセットを処理し、汎用ログ機能を追加してコードをより効率的、柔軟で保守しやすいものにする方法を示します。

おすすめ

転載: blog.csdn.net/qq_35831906/article/details/131983269