Python でクロージャとデコレータをマスターする: 基本から上級まで

DDD
リリース: 2024-09-19 01:39:33
オリジナル
605 人が閲覧しました

Mastering Closures and Decorators in Python: From Basics to Advanced

導入

クロージャとデコレータは、より柔軟で再利用可能なコードを作成できる Python の強力な機能です。これらの概念を理解すると、Python スキルが次のレベルに上がり、ロギング、アクセス制御、メモ化などのより複雑なシナリオを簡単に処理できるようになります。

このブログ投稿では、以下について説明します。

  1. クロージャーとは何ですか?
  2. Python でクロージャがどのように機能するかを理解する
  3. クロージャーの使用例
  4. デコレータとは何ですか?
  5. デコレーターの仕組みを理解する
  6. 組み込みデコレータの使用
  7. カスタムデコレータの作成
  8. デコレーターを使用した高度なコンセプト

この記事を終えるまでに、クロージャとデコレータをしっかりと理解し、独自のコードにそれらを効果的に適用できるようになります。

クロージャとは何ですか?

Python の クロージャ は、外側の関数の実行が終了した場合でも、外側の字句スコープから変数の値を保持する関数です。クロージャは関数呼び出し間の状態を保持する方法であり、コンテキストを維持する必要があるシナリオに役立ちます。

クロージャは 3 つの主要コンポーネントで構成されます:

  1. 入れ子関数
  2. 囲んでいる関数内の自由変数への参照
  3. 囲んでいる関数は実行を終了しましたが、入れ子になった関数は自由変数の状態をまだ記憶しています。

クロージャの基本的な例

簡単なクロージャの例を次に示します:

def outer_function(message):
    def inner_function():
        print(message)
    return inner_function

# Create a closure
closure = outer_function("Hello, World!")
closure()  # Output: Hello, World!
ログイン後にコピー

この例では、inner_function は、outer_function の実行が終了した後でも、outer_function からのメッセージ変数を参照します。内部関数は外部スコープから変数を「閉じる」ため、クロージャー.

という用語が生まれます。

クロージャーが内部的にどのように機能するか

クロージャは、自由変数の状態をキャプチャし、関数オブジェクトの __closure__ 属性に格納することによって機能します。

前の例のクロージャーを調べてみましょう:

print(closure.__closure__[0].cell_contents)  # Output: Hello, World!
ログイン後にコピー

__closure__ 属性は、クロージャが保持する変数への参照を保持します。各変数は「セル」に保存され、cell_contents を使用してその内容にアクセスできます。

クロージャの使用例

クロージャは、グローバル変数やクラスを使用せずに関数呼び出し間の状態を維持したい場合に特に便利です。一般的な使用例をいくつか示します:

1. 関数ファクトリー

クロージャを使用して関数を動的に作成できます。

def multiplier(factor):
    def multiply_by_factor(number):
        return number * factor
    return multiply_by_factor

times_two = multiplier(2)
times_three = multiplier(3)

print(times_two(5))  # Output: 10
print(times_three(5))  # Output: 15
ログイン後にコピー

この例では、multiplier は、指定された数値に特定の係数を乗算する関数を返します。クロージャー times_two と times_three は、それらを囲んでいるスコープからの因子の値を保持します。

2. カプセル化

クロージャを使用すると、内部状態を公開せずに動作をカプセル化できます。これは、オブジェクト指向プログラミングにおけるプライベート メソッドの概念に似ています。

def counter():
    count = 0
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

counter_fn = counter()
print(counter_fn())  # Output: 1
print(counter_fn())  # Output: 2
ログイン後にコピー

この例では、count 変数はクロージャ内にカプセル化されており、その値を変更できるのはインクリメント関数のみです。

デコレータとは何ですか?

デコレータは、別の関数を受け取り、元の関数のコードを変更せずにその動作を拡張または変更する関数です。デコレーターは、ログ、アクセス制御、タイミングなどの機能を関数やメソッドに追加するためによく使用されます。

Python では、関数定義の上にある @ 記号を使用してデコレーターが関数に適用されます。

デコレータの基本的な例

def decorator_function(original_function):
    def wrapper_function():
        print(f"Wrapper executed before {original_function.__name__}()")
        return original_function()
    return wrapper_function

@decorator_function
def say_hello():
    print("Hello!")

say_hello()

# Output:
# Wrapper executed before say_hello()
# Hello!
ログイン後にコピー

ここでは、decorator_function がsay_hello に適用され、say_hello() が実行される前に追加の機能が追加されます。

デコレーターの仕組み

デコレータは本質的に、Python の一般的なパターン、つまり他の関数を引数として受け取る高階関数の糖衣構文です。 @decorator を記述すると、次と同等になります:

say_hello = decorator_function(say_hello)
ログイン後にコピー

デコレーター関数は、元の関数の動作を拡張する新しい関数 (wrapper_function) を返します。

引数を持つデコレータ

装飾される関数が引数を取る場合、ラッパー関数は引数を渡すために *args と **kwargs を受け入れる必要があります。

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print(f"Wrapper executed before {original_function.__name__}()")
        return original_function(*args, **kwargs)
    return wrapper_function

@decorator_function
def display_info(name, age):
    print(f"display_info ran with arguments ({name}, {age})")

display_info("John", 25)

# Output:
# Wrapper executed before display_info()
# display_info ran with arguments (John, 25)
ログイン後にコピー

Python の組み込みデコレータ

Python には、@staticmethod、@classmethod、@property などのいくつかの組み込みデコレータが用意されています。

@staticmethod and @classmethod

These decorators are commonly used in object-oriented programming to define methods that are either not bound to the instance (@staticmethod) or bound to the class itself (@classmethod).

class MyClass:
    @staticmethod
    def static_method():
        print("Static method called")

    @classmethod
    def class_method(cls):
        print(f"Class method called from {cls}")

MyClass.static_method()   # Output: Static method called
MyClass.class_method()    # Output: Class method called from <class '__main__.MyClass'>
ログイン後にコピー

@property

The @property decorator allows you to define a method that can be accessed like an attribute.

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value <= 0:
            raise ValueError("Radius must be positive")
        self._radius = value

c = Circle(5)
print(c.radius)  # Output: 5

c.radius = 10
print(c.radius)  # Output: 10
ログイン後にコピー

Writing Custom Decorators

You can write your own decorators to add custom functionality to your functions or methods. Decorators can be stacked, meaning you can apply multiple decorators to a single function.

Example: Timing a Function

Here’s a custom decorator that measures the execution time of a function:

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} ran in {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timer_decorator
def calculate_square(numbers):
    result = [n * n for n in numbers]
    return result

nums = range(1, 1000000)
calculate_square(nums)
ログイン後にコピー

Decorators with Arguments

Decorators can also accept their own arguments. This is useful when you need to pass configuration values to the decorator.

Example: Logger with Custom Message

def logger_decorator(message):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"{message}: Executing {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@logger_decorator("DEBUG")
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

# Output:
# DEBUG: Executing greet
# Hello, Alice!
ログイン後にコピー

In this example, the decorator logger_decorator takes a message as an argument, and then it wraps the greet function with additional logging functionality.

Advanced Decorator Concepts

1. Decorating Classes

Decorators can be applied not only to functions but also to classes. Class decorators modify or extend the behavior of entire classes.

def add_str_repr(cls):
    cls.__str__ = lambda self: f"Instance of {cls.__name__}"
    return cls

@add_str_repr
class Dog:
    pass

dog = Dog()
print(dog)  # Output: Instance of Dog
ログイン後にコピー

2. Memoization with Decorators

Memoization is an optimization technique where the results of expensive function calls are cached, so subsequent calls with the same arguments can be returned faster.

def memoize(func):
    cache = {}
    def wrapper(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrapper

@memoize
def fibonacci(n):


 if n in [0, 1]:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(30))  # Output: 832040
ログイン後にコピー

Conclusion

Closures and decorators are advanced Python concepts that unlock powerful capabilities for writing cleaner, more efficient code. Closures allow you to maintain state and encapsulate data, while decorators let you modify or extend the behavior of functions and methods in a reusable way. Whether you're optimizing performance with memoization, implementing access control, or adding logging, decorators are an essential tool in your Python toolkit.

By mastering these concepts, you'll be able to write more concise and maintainable code and handle complex programming tasks with ease.

Feel free to experiment with closures and decorators in your projects and discover how they can make your code more elegant and powerful!


Connect with Me

  • GitHub
  • Linkedin

以上がPython でクロージャとデコレータをマスターする: 基本から上級までの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート