如何创建函数装饰器

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

函数装饰器是 Python 中一项强大且优雅的特性,它允许开发者在不直接修改函数源代码的情况下,修改或增强函数的行为。本教程将探讨创建和使用函数装饰器的基础知识,深入了解如何使用它们来编写更灵活、更易于维护的 Python 代码。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/arguments_return("Arguments and Return Values") python/FunctionsGroup -.-> python/lambda_functions("Lambda Functions") python/FunctionsGroup -.-> python/scope("Scope") python/AdvancedTopicsGroup -.-> python/decorators("Decorators") subgraph Lab Skills python/function_definition -.-> lab-419809{{"如何创建函数装饰器"}} python/arguments_return -.-> lab-419809{{"如何创建函数装饰器"}} python/lambda_functions -.-> lab-419809{{"如何创建函数装饰器"}} python/scope -.-> lab-419809{{"如何创建函数装饰器"}} python/decorators -.-> lab-419809{{"如何创建函数装饰器"}} end

装饰器基础

什么是装饰器?

在 Python 中,装饰器是一种强大且优雅的方式,用于在不直接更改函数和方法的源代码的情况下修改或增强它们。它们本质上是将另一个函数作为参数,并返回该函数的修改版本的函数。

基本语法和概念

装饰器通过在函数定义的正上方使用 @ 符号后跟装饰器函数名来实现:

def my_decorator(func):
    def wrapper():
        print("函数调用前的一些操作。")
        func()
        print("函数调用后的一些操作。")
    return wrapper

@my_decorator
def say_hello():
    print("你好!")

say_hello()

装饰器的工作原理

graph LR A[原始函数] --> B[装饰器函数] B --> C[包装函数] C --> D[增强的功能]

装饰器的类型

装饰器类型 描述 使用场景
函数装饰器 修改函数行为 日志记录、计时、认证
类装饰器 修改类行为 单例模式、类注册
方法装饰器 修改方法行为 缓存、验证

关键特性

  • 装饰器是可调用对象
  • 它们可以嵌套
  • 它们使用 functools.wraps 保留原始函数的元数据
  • 它们可以接受参数

在 LabEx 中的简单示例

以下是一个在 LabEx Python 环境中演示装饰器的实际示例:

def log_execution(func):
    def wrapper(*args, **kwargs):
        print(f"正在执行函数:{func.__name__}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 执行完毕")
        return result
    return wrapper

@log_execution
def calculate_sum(a, b):
    return a + b

result = calculate_sum(5, 3)
print(result)

常见用例

  • 性能监控
  • 认证和授权
  • 日志记录
  • 缓存
  • 输入验证

理解装饰器对于编写更模块化和可维护的 Python 代码至关重要,它使开发者能够在不修改现有代码的情况下扩展功能。

函数装饰器

深入理解函数装饰器

函数装饰器是 Python 中的一种强大机制,它允许在运行时动态修改函数。它们提供了一种简洁且可复用的方式来扩展或改变函数行为,而无需直接修改原始函数。

基本函数装饰器结构

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        ## 函数执行前的逻辑
        result = original_function(*args, **kwargs)
        ## 函数执行后的逻辑
        return result
    return wrapper_function

装饰器工作流程

graph LR A[原始函数] --> B[装饰器函数] B --> C[包装函数] C --> D[增强的功能]

高级装饰器技术

带参数的装饰器

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

@repeat(times=3)
def greet(name):
    print(f"你好, {name}!")

greet("LabEx 用户")

多个装饰器

def decorator1(func):
    def wrapper(*args, **kwargs):
        print("装饰器 1")
        return func(*args, **kwargs)
    return wrapper

def decorator2(func):
    def wrapper(*args, **kwargs):
        print("装饰器 2")
        return func(*args, **kwargs)
    return wrapper

@decorator1
@decorator2
def example_function():
    print("原始函数")

example_function()

装饰器类型

装饰器类型 描述 示例用例
简单装饰器 修改函数行为 日志记录
参数化装饰器 接受参数 重试机制
类装饰器 修改类方法 验证

保留函数元数据

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        """包装函数文档字符串"""
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example_func():
    """原始函数文档字符串"""
    pass

性能考量

  • 装饰器会引入轻微的性能开销
  • 使用 functools.wraps 保留函数元数据
  • 注意嵌套装饰器

LabEx 实际示例:计时装饰器

import time

def timing_decorator(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

@timing_decorator
def complex_calculation():
    return sum(range(1000000))

complex_calculation()

最佳实践

  • 保持装饰器简单且功能集中
  • 使用 functools.wraps 保留函数元数据
  • 考虑性能影响
  • 清晰记录装饰器行为

函数装饰器提供了一种灵活且优雅的方式来修改函数行为,使 Python 代码更具模块化和可维护性。

实际应用场景

装饰器应用介绍

装饰器是 Python 中用途广泛的工具,在软件开发的不同领域有众多实际应用。

常见实际应用场景

1. 日志记录与监控

def log_function_call(func):
    def wrapper(*args, **kwargs):
        print(f"正在调用函数:{func.__name__}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 已完成")
        return result
    return wrapper

@log_function_call
def calculate_total(items):
    return sum(items)

calculate_total([1, 2, 3, 4, 5])

2. 性能计时

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 耗时 {end - start:.4f} 秒")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(2)
    return "已完成"

slow_function()

认证与授权

def require_auth(func):
    def wrapper(*args, **kwargs):
        user = kwargs.get('user')
        if not user or not user.is_authenticated:
            raise PermissionError("需要认证")
        return func(*args, **kwargs)
    return wrapper

class User:
    def __init__(self, authenticated=False):
        self.is_authenticated = authenticated

@require_auth
def access_sensitive_data(user):
    return "敏感信息"

## 使用示例
authenticated_user = User(authenticated=True)
unauthenticated_user = User()

try:
    access_sensitive_data(user=authenticated_user)
    access_sensitive_data(user=unauthenticated_user)
except PermissionError as e:
    print(e)

缓存机制

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 < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(30))  ## 重复调用时速度显著加快

装饰器用例比较

用例 目的 主要优点
日志记录 跟踪函数调用 调试
认证 控制访问 安全
缓存 存储函数结果 性能提升
计时 测量执行时间 优化

输入验证

def validate_inputs(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, (int, float)):
                raise ValueError("仅允许数字输入")
        return func(*args, **kwargs)
    return wrapper

@validate_inputs
def divide_numbers(a, b):
    return a / b

try:
    print(divide_numbers(10, 2))
    print(divide_numbers(10, "2"))  ## 引发 ValueError
except ValueError as e:
    print(e)

使用 LabEx 进行速率限制

def rate_limit(max_calls=3, time_frame=60):
    calls = []
    def decorator(func):
        def wrapper(*args, **kwargs):
            import time
            current_time = time.time()
            calls[:] = [call for call in calls if current_time - call < time_frame]

            if len(calls) >= max_calls:
                raise Exception("速率限制已超出")

            calls.append(current_time)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@rate_limit(max_calls=2, time_frame=10)
def api_request():
    print("API 请求已处理")

## 演示速率限制机制

最佳实践

  • 保持装饰器功能集中且单一用途
  • 使用 functools.wraps 保留函数元数据
  • 考虑性能影响
  • 优雅地处理潜在异常

装饰器提供了一种强大的方式来扩展和修改函数行为,而无需更改其核心实现,使 Python 代码更具模块化和可维护性。

总结

通过理解函数装饰器,Python 开发者可以掌握高级元编程技术,实现动态函数修改、日志记录、认证、性能跟踪等功能。掌握装饰器使程序员能够以最小的复杂度编写更简洁、更模块化、更高效的代码。