面向高级程序员的 Python 装饰器指南

Python 装饰器是一种功能强大且灵活的工具,可用于修改函数或方法的行为。它们允许程序员以干净、可读且可维护的方式扩展或更改可调用对象的功能。本文探讨与 Python 装饰器相关的高级概念,包括嵌套装饰器、装饰器参数和基于类的装饰器。

什么是装饰器?

装饰器是修改另一个函数行为的函数。它们包装另一个函数以扩展其行为,而无需明确修改其代码。装饰器使用 @decorator_name 语法定义,并放置在函数定义之上。

基本装饰器语法

一个简单的装饰器以一个函数作为参数,定义一个添加一些行为的内部函数,然后返回该内部函数。

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()

带参数的装饰函数

通过接受参数,装饰器可以变得更加灵活。要创建这样的装饰器,您需要编写一个返回装饰器的函数。这可以为装饰器添加更多动态行为。

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

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

greet("Alice")

嵌套装饰器

装饰器可以嵌套使用,以组合多种行为。例如,我们可以在一个函数上使用两个或多个装饰器。

def uppercase_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def repeat_decorator(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + result
    return wrapper

@repeat_decorator
@uppercase_decorator
def say_word(word):
    return word

print(say_word("hello"))

基于类的装饰器

在 Python 中,装饰器也可以通过使用 __call__ 方法作为类来实现。当您需要更复杂的状态管理和行为时,基于类的装饰器非常有用。

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

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

say_hello()
say_hello()

使用 functools.wraps 保存元数据

当您编写装饰器时,被装饰的函数会丢失其原始元数据,例如其名称和文档字符串。 functools.wraps 装饰器可用于将原始函数的元数据复制到包装函数。

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper function executed before", func.__name__)
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def display_info(name, age):
    """Displays name and age."""
    print(f"display_info ran with arguments ({name}, {age})")

print(display_info.__name__)  # Output: display_info
print(display_info.__doc__)   # Output: Displays name and age.

结论

Python 装饰器是一项强大的功能,可实现灵活的代码设计和行为修改。高级用法(例如嵌套装饰器、带参数的装饰器和基于类的装饰器)可以为 Python 程序提供更多功能和可读性。通过正确理解和使用装饰器,开发人员可以编写更简洁、高效且可读的代码。