Python 装饰器的用法

Python 装饰器的用法

1. 什么是装饰器?

装饰器(Decorator)是 Python 中的一个设计模式,它允许在不修改函数定义的情况下,向函数添加额外的功能。装饰器本质上是一个高阶函数,即接受函数作为参数并返回一个新函数。装饰器通常用于日志记录、性能测试、权限验证等场景。

装饰器的基本语法是通过在函数定义前加上 @decorator_name 来实现的。

2. 装饰器的定义与基本使用

示例1:最简单的装饰器

以下是一个最简单的装饰器示例,它在原函数调用前后打印日志信息。

def my_decorator(func):
    def wrapper():
        print("执行函数前的操作")
        func()
        print("执行函数后的操作")
    return wrapper

# 使用装饰器
@my_decorator
def say_hello():
    print("Hello, World!")

say_hello()
代码说明
  • my_decorator(func):这是装饰器函数,它接收另一个函数 func 作为参数,并返回一个新的函数 wrapper
  • wrapper():在 wrapper 函数中,我们在原函数调用前后添加了自定义操作。
  • @my_decorator:这一行代码相当于 say_hello = my_decorator(say_hello)。每当调用 say_hello() 时,实际上执行的是 wrapper() 函数。
输出
执行函数前的操作
Hello, World!
执行函数后的操作

3. 带参数的装饰器

装饰器不仅可以作用于无参函数,还可以处理带参数的函数。

示例2:处理带参数的函数
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("执行函数前的操作")
        result = func(*args, **kwargs)
        print("执行函数后的操作")
        return result
    return wrapper

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

greet("Alice")
代码说明
  • *args, **kwargs:这是 Python 中用于接收任意数量的位置参数和关键字参数的语法。通过它,装饰器可以处理各种参数组合的函数。
  • func(*args, **kwargs):将原函数的参数传递给它。
输出
执行函数前的操作
Hello, Alice!
执行函数后的操作

4. 多个装饰器的使用

在 Python 中,你可以对同一个函数应用多个装饰器。装饰器的执行顺序是从内向外,即最靠近函数的装饰器最先执行。

示例3:多个装饰器的应用
def decorator_1(func):
    def wrapper():
        print("装饰器1 - 前")
        func()
        print("装饰器1 - 后")
    return wrapper

def decorator_2(func):
    def wrapper():
        print("装饰器2 - 前")
        func()
        print("装饰器2 - 后")
    return wrapper

@decorator_1
@decorator_2
def say_hello():
    print("Hello!")

say_hello()
代码说明
  • 装饰器应用顺序@decorator_2 最先应用,所以 decorator_2 包裹了原函数 say_hello。然后 decorator_1 包裹了 decorator_2 的返回结果。
输出
装饰器1 - 前
装饰器2 - 前
Hello!
装饰器2 - 后
装饰器1 - 后

5. 装饰器的实际应用

5.1 用于记录函数执行时间

装饰器非常适合用于性能分析,下面的示例会记录函数的执行时间。

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"函数 {
      
      func.__name__} 执行时间: {
      
      end_time - start_time:.4f} 秒")
        return result
    return wrapper

@timer
def example_function():
    time.sleep(2)

example_function()
代码说明
  • time.time():记录当前时间,函数执行前后都调用该函数,计算两者差值即为执行时间。
输出
函数 example_function 执行时间: 2.0001 秒
5.2 权限验证

装饰器在 Web 开发中常用于权限验证。假设我们需要验证某个用户是否具有执行某项操作的权限,可以使用装饰器实现。

def check_permission(user_role):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if user_role != 'admin':
                print("权限不足,无法执行此操作")
                return
            return func(*args, **kwargs)
        return wrapper
    return decorator

@check_permission(user_role='admin')
def delete_user():
    print("用户已删除")

@check_permission(user_role='guest')
def add_user():
    print("用户已添加")

delete_user()  # admin 执行操作
add_user()     # guest 尝试执行操作
代码说明
  • check_permission(user_role):这是一个带参数的装饰器,用来检查用户的角色是否为 ‘admin’,如果权限不足则阻止函数执行。
输出
用户已删除
权限不足,无法执行此操作

6. 装饰器实现的缓存机制

通过装饰器实现缓存(memoization)可以提高函数的效率,尤其是在处理耗时计算时。

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

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(10))  # 输出55
代码说明
  • cache:使用字典缓存已计算的 Fibonacci 结果,避免重复计算,提高效率。

7. 带参数的装饰器

装饰器本身可以接受参数。通过这一功能,我们可以创建更加灵活的装饰器。

示例:带参数的装饰器
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()
代码说明
  • repeat(times):这是一个装饰器工厂,接收参数 times,并生成真正的装饰器 decorator
  • for _ in range(times):函数被调用多次,次数由装饰器的参数决定。
输出
Hello!
Hello!
Hello!

8. 结论

Python 装饰器是一个功能强大且灵活的工具,能够为函数添加额外功能,而无需修改函数本身。它通过封装逻辑,使代码更加简洁和可维护。装饰器特别适合用于日志记录、权限验证、性能分析等应用场景。尽管装饰器的使用非常灵活,但在代码过度复杂的情况下,应避免滥用装饰器,以保持代码的可读性。