>백엔드 개발 >파이썬 튜토리얼 >Python의 클로저와 데코레이터 익히기: 기초부터 고급까지

Python의 클로저와 데코레이터 익히기: 기초부터 고급까지

DDD
DDD원래의
2024-09-19 01:39:33606검색

Mastering Closures and Decorators in Python: From Basics to Advanced

소개

클로저와 데코레이터는 더 유연하고 재사용 가능한 코드를 작성할 수 있게 해주는 Python의 강력한 기능입니다. 이러한 개념을 이해하면 Python 기술을 한 단계 더 발전시켜 로깅, 액세스 제어, 메모와 같은 보다 복잡한 시나리오를 쉽게 처리할 수 있습니다.

이 블로그 게시물에서 살펴볼 내용은 다음과 같습니다.

  1. 폐쇄란 무엇인가요?
  2. Python에서 클로저 작동 방식 이해
  3. 폐쇄 사용 사례
  4. 데코레이터란 무엇인가요?
  5. 데코레이터 작동 방식 이해
  6. 내장 데코레이터 사용
  7. 맞춤 데코레이터 작성
  8. 데코레이터를 사용한 고급 개념

이 글을 마치면 클로저와 데코레이터에 대해 확실히 이해하고 이를 자신의 코드에 효과적으로 적용할 수 있을 것입니다.

폐쇄란 무엇인가요?

Python에서 클로저는 외부 함수의 실행이 완료된 경우에도 바깥쪽 어휘 범위의 변수 값을 유지하는 함수입니다. 클로저는 함수 호출 간에 상태를 유지하는 방법이므로 일부 컨텍스트를 유지해야 하는 시나리오에 유용합니다.

클로저는 세 가지 주요 구성 요소로 구성됩니다.

  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은 external_function의 실행이 완료된 후에도 external_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_3은 포함 범위의 요소 값을 유지합니다.

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.