Python 装饰器详解
                           
天天向上
发布: 2025-03-14 22:48:56

原创
675 人浏览过

装饰器(Decorator)是 Python 中一种非常强大的功能,允许我们在不修改函数或方法本体的情况下,增强其功能。它通常用于函数的包装,使得原本简单的函数能够变得更加灵活和功能强大。装饰器的本质是接受一个函数作为参数,并返回一个新的函数。它可以用来修改或扩展原函数的行为。


1. 装饰器的基本语法

装饰器通常有以下两种定义方式:

def decorator_function(func):
    def wrapper():
        # 可以在原函数调用前后增加功能
        print("Before function call")
        func()  # 调用原函数
        print("After function call")
    return wrapper

然后,我们可以使用 @ 符号将装饰器应用到函数上:

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

这个 @decorator_function 是装饰器语法糖,实际上等价于:

say_hello = decorator_function(say_hello)

2. 装饰器工作原理

  1. 原函数say_hello 函数定义了它的行为。
  2. 装饰器decorator_function 接受原函数 say_hello 作为参数。
  3. 包装函数wrapper 是装饰器中的内嵌函数,它在原函数执行前后可以加入额外的逻辑。

示例 1:最基本的装饰器

def decorator_function(func):
    def wrapper():
        print("Before function call")
        func()  # 调用原函数
        print("After function call")
    return wrapper

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

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

# 输出:
# Before function call
# Hello!
# After function call

3. 带参数的装饰器

如果原函数带有参数,装饰器中的 wrapper 也需要接受这些参数并将其传递给原函数。

示例 2:带参数的装饰器

def decorator_function(func):
    def wrapper(*args, **kwargs):  # 接受任意数量的参数
        print("Before function call")
        result = func(*args, **kwargs)  # 将参数传递给原函数
        print("After function call")
        return result
    return wrapper

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

greet("Alice")

# 输出:
# Before function call
# Hello, Alice!
# After function call

在上面的示例中,*args**kwargs 允许装饰器函数处理任意类型的参数。


4. 带返回值的装饰器

装饰器可以在原函数执行前、执行后或替代原函数返回结果。

示例 3:返回值的装饰器

def decorator_function(func):
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)  # 获取原函数的返回值
        print("After function call")
        return result  # 返回原函数的结果
    return wrapper

@decorator_function
def add(a, b):
    return a + b

result = add(5, 7)
print(f"Result: {result}")

# 输出:
# Before function call
# After function call
# Result: 12

5. 带参数和返回值的装饰器

装饰器不仅可以修改函数的行为,还可以增强函数的功能,比如日志记录、权限校验等。

示例 4:带参数和返回值的装饰器

def decorator_function(func):
    def wrapper(*args, **kwargs):
        print(f"Arguments were: {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"Returned: {result}")
        return result
    return wrapper

@decorator_function
def multiply(x, y):
    return x * y

multiply(3, 4)

# 输出:
# Arguments were: (3, 4), {}
# Returned: 12

6. 装饰器的应用

装饰器广泛应用于各种场景,如:

  • 日志记录:记录函数的调用、参数和返回值。
  • 权限校验:确保用户拥有访问某个资源的权限。
  • 性能监测:测量函数执行时间。
  • 缓存:存储和复用函数结果,避免重复计算。

7. 装饰器链

多个装饰器可以叠加在同一个函数上,装饰器会按照从内到外的顺序执行。

示例 5:装饰器链

def decorator1(func):
    def wrapper():
        print("Decorator 1")
        return func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        return func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()

# 输出:
# Decorator 1
# Decorator 2
# Hello!

8. functools.wraps:保持函数元数据

当使用装饰器时,原函数的元数据(如函数名、文档字符串等)会被 wrapper 函数覆盖。为了保留原函数的元数据,可以使用 functools.wraps

示例 6:使用 wraps

from functools import wraps

def decorator_function(func):
    @wraps(func)  # 保留原函数的元数据
    def wrapper(*args, **kwargs):
        print("Before function call")
        return func(*args, **kwargs)
    return wrapper

@decorator_function
def say_hello():
    """A simple greeting function"""
    print("Hello!")

print(say_hello.__name__)  # 输出 say_hello
print(say_hello.__doc__)   # 输出 A simple greeting function

9. 总结

  • 装饰器 是一种设计模式,可以修改函数或方法的行为而不直接修改它们的源代码。
  • 它们广泛应用于函数增强、日志记录、权限验证、缓存、性能监控等场景。
  • 装饰器使用 @ 语法应用,可以带有参数、返回值,并且支持链式使用。
  • 使用 functools.wraps 可以保留原函数的元数据。

更多详细内容请关注其他相关!

发表回复 0

Your email address will not be published. Required fields are marked *