当前位置:首页 > Python > 正文内容

Python 装饰器高级用法与实战应用

admin2周前 (03-24)Python19

装饰器(Decorator)是 Python 中最强大的特性之一,它允许我们在不修改原有函数代码的情况下,动态地扩展函数的功能。本文将深入探讨装饰器的高级用法,并通过实际代码示例展示其在项目中的应用场景。

装饰器基础回顾

装饰器本质上是接受一个函数作为参数,并返回一个新函数的高阶函数。最简单的装饰器形式如下:

def simple_decorator(func):
    def wrapper():
        print("执行前")
        result = func()
        print("执行后")
        return result
    return wrapper

@simple_decorator
def greet():
    return "Hello, World!"

greet()  # 输出:执行前 -> Hello, World! -> 执行后

带参数的装饰器

实际应用中,我们经常需要创建可配置的装饰器。这需要使用装饰器工厂模式:

def repeat(times=1):
    def decorator(func):
        def wrapper(*args, **kwargs):
            results = []
            for _ in range(times):
                results.append(func(*args, **kwargs))
            return results if len(results) > 1 else results[0]
        return wrapper
    return decorator

@repeat(times=3)
def say_hello(name):
    return f"Hello, {name}!"

print(say_hello("Alice"))  # ['Hello, Alice!', 'Hello, Alice!', 'Hello, Alice!']

保留函数元信息

使用装饰器时,原始函数的元信息会被 wrapper 函数覆盖。Python 提供了 functools.wraps 装饰器来解决这个问题:

from functools import wraps
import time

def timing(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()
        print(f"{func.__name__} 执行时间: {end - start:.6f} 秒")
        return result
    return wrapper

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

print(fibonacci(10))

类装饰器

装饰器不仅可以是函数,也可以是类。类装饰器通过 __call__ 方法实现:

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
        functools.update_wrapper(self, func)

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} 已被调用 {self.count} 次")
        return self.func(*args, **kwargs)

@CountCalls
def process_data(data):
    return f"处理数据: {data}"

process_data([1, 2, 3])

装饰器堆叠

多个装饰器可以叠加使用,执行顺序从内到外(从下到上):

def uppercase(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper() if isinstance(result, str) else result
    return wrapper

def exclaim(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return f"{result}!" if isinstance(result, str) else result
    return wrapper

@uppercase
@exclaim
def greet(name):
    return f"hello, {name}"

print(greet("Bob"))  # 输出:HELLO, BOB!

带状态的装饰器

装饰器可以维护内部状态,在多次调用间共享数据。下面实现一个带大小限制的缓存装饰器:

def cache(max_size=128):
    cache_dict = {}
    access_order = []

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            key = (args, frozenset(kwargs.items()))

            if key in cache_dict:
                access_order.remove(key)
                access_order.append(key)
                return cache_dict[key]

            result = func(*args, **kwargs)

            if len(cache_dict) >= max_size and key not in cache_dict:
                oldest_key = access_order.pop(0)
                del cache_dict[oldest_key]

            cache_dict[key] = result
            access_order.append(key)
            return result

        wrapper.clear_cache = lambda: (cache_dict.clear(), access_order.clear())
        return wrapper
    return decorator

@cache(max_size=3)
def expensive_computation(x):
    print(f"执行复杂计算: {x}")
    return x ** 2

print(expensive_computation(5))
print(expensive_computation(5))  # 缓存命中

参数验证装饰器

装饰器非常适合用于函数参数验证:

import inspect

def validate_types(**type_checks):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            sig = inspect.signature(func)
            bound_args = sig.bind(*args, **kwargs)
            bound_args.apply_defaults()

            for param_name, expected_type in type_checks.items():
                if param_name in bound_args.arguments:
                    value = bound_args.arguments[param_name]
                    if not isinstance(value, expected_type):
                        raise TypeError(f"参数 '{param_name}' 类型错误")

            return func(*args, **kwargs)
        return wrapper
    return decorator

@validate_types(name=str, age=int, scores=list)
def register_student(name, age, scores):
    return f"注册学生: {name}, {age}岁, 成绩: {scores}"

print(register_student("张三", 18, [90, 85, 92]))

异常处理装饰器

统一的异常处理可以通过装饰器实现:

def handle_exceptions(default_return=None, log_errors=True):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except ValueError as e:
                if log_errors:
                    print(f"值错误: {e}")
                return default_return
            except Exception as e:
                if log_errors:
                    print(f"未知错误: {e}")
                return default_return
        return wrapper
    return decorator

@handle_exceptions(default_return=None)
def parse_int(value):
    return int(value)

print(parse_int("123"))    # 123
print(parse_int("abc"))    # None

重试机制装饰器

在调用外部 API 或不稳定服务时,重试机制非常有用:

def retry(max_attempts=3, delay=1, backoff=2):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            attempts = 0
            current_delay = delay

            while attempts < max_attempts:
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    attempts += 1
                    if attempts == max_attempts:
                        raise

                    print(f"尝试 {attempts}/{max_attempts} 失败")
                    time.sleep(current_delay)
                    current_delay *= backoff
        return wrapper
    return decorator

实战应用:API 请求限流

下面实现一个简单的限流器装饰器,控制 API 请求的频率:

class RateLimiter:
    def __init__(self, max_calls=10, time_window=60):
        self.max_calls = max_calls
        self.time_window = time_window
        self.calls = []

    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            now = time.time()

            self.calls = [t for t in self.calls if now - t < self.time_window]

            if len(self.calls) >= self.max_calls:
                wait_time = self.time_window - (now - self.calls[0])
                raise Exception(f"超过限流,请等待 {wait_time:.1f} 秒")

            self.calls.append(now)
            return func(*args, **kwargs)

        return wrapper

@RateLimiter(max_calls=3, time_window=10)
def api_request(endpoint):
    return f"请求 {endpoint} 成功"

总结

Python 装饰器是一个强大而灵活的工具,通过本文的学习,你应该掌握了:

  1. 基础装饰器 - 理解装饰器的核心概念
  2. 带参数装饰器 - 创建可配置的装饰器
  3. 类装饰器 - 使用类实现更复杂的装饰逻辑
  4. 装饰器堆叠 - 组合多个装饰器
  5. 带状态装饰器 - 维护调用间的状态
  6. 实用场景 - 缓存、限流、重试、验证等

在实际项目中,合理使用装饰器可以大大提高代码的可读性和可维护性,减少重复代码,实现横切关注点的优雅解耦。装饰器的核心思想是"不修改原代码,动态扩展功能",这正是 Pythonic 风格的体现。

相关文章

Python 上下文管理器的 5 个实用技巧,让你的代码更优雅

在 Python 编程中,上下文管理器(Context Manager)是一个优雅的资源管理工具。你可能已经熟悉最常见的用法——使用 with 语句打开文件,但上下文管理器的能力远不止于此。今天,我将...

Python 上下文管理器实战:从 with 语句到自定义资源管理

在 Python 编程中,上下文管理器(Context Manager)是一个强大但常被低估的特性。当你使用 open() 函数读取文件时,那个熟悉的 with 语句背后,正是上下文管理器在默默工作。...

Python 装饰器实用指南:从入门到精通

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。这个概念听起来有些抽象,但让我们通过一个具体的例子来理解它的实际价值。想象一下,你正在开发一个 Web 应用,需要记录每个函数的执行时间。如果...

Python 装饰器的实用技巧与高级用法

装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。理解这一点是掌握装饰器的关键。让我们从最简单的例子开始,逐步深入到复杂的应用场景。首先,我们需要理解函数在 Python 中是一等公民。这意味...

Python装饰器实战指南:从入门到精通

Python 装饰器是许多开发者既熟悉又陌生的功能。熟悉是因为我们在框架中经常看到 @符号,陌生是因为很多人只是知其然不知其所以然。本文将从零开始,通过实际案例深入讲解装饰器的工作原理和应用场景。...

Python异步编程入门与实战

异步编程是一种并发执行的编程模式,它允许程序在等待耗时操作(如网络请求、文件读写)时,继续执行其他任务。Python 3.5引入了async/await语法,使得异步编程变得更加直观和易于理解。为什么...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。