目 录CONTENT

文章目录

Python装饰器学习

Administrator
2025-09-28 / 0 评论 / 0 点赞 / 0 阅读 / 0 字

 

字数 8884,阅读大约需 45 分钟

Decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.(Python装饰器是一种设计模式,它允许你在不修改原函数代码的情况下,给函数添加新的功能。装饰器本质上是一个接受函数作为参数并返回一个新函数的高阶函数。)

1. 基础概念

装饰器的定义和作用

装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数。它的主要作用是在不修改原函数代码的情况下,为函数添加额外的功能,例如日志记录、性能计时、权限验证等。

高阶函数的概念

高阶函数是指满足以下任一条件的函数:

  1. 1. 接收一个或多个函数作为参数。

  2. 2. 返回一个函数。

函数作为一等公民的理解

在 Python 中,函数被视为“一等公民”,这意味着函数可以:

  • • 被赋值给变量。

  • • 作为参数传递给其他函数。

  • • 作为其他函数的返回值。

  • • 存储在数据结构中(如列表、字典)。

示例代码:


    
    
    
  def greet(name):
    """一个简单的问候函数"""
    return f"Hello, {name}"

def wrapper(func):
    """一个高阶函数,接收并返回一个函数"""
    def inner(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return inner

wrapped_greet = wrapper(greet)
print(wrapped_greet("Alice"))

装饰器的语法糖 @decorator

Python 提供了 @decorator 语法糖,使得装饰器的使用更加简洁和优雅。
@wrapper 等同于 say_hello = wrapper(say_hello)

示例代码:


    
    
    
  @wrapper
def say_hello(name):
    """使用装饰器语法糖的问候函数"""
    return f"Hello, {name} from say_hello"

print(say_hello("Bob"))

2. 函数装饰器基础

简单装饰器的实现

一个简单的函数装饰器通常包含一个外层函数(装饰器本身)和一个内层函数(包装器)。

示例代码:


    
    
    
  import functools

def simple_decorator(func):
    """一个简单的函数装饰器"""
    def wrapper_func(*args, **kwargs):
        print(f"Calling function {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Function {func.__name__} finished")
        return result
    return wrapper_func

@simple_decorator
def my_function():
    """被简单装饰器装饰的函数"""
    print("Inside my_function")

my_function()

装饰器的执行时机

装饰器在被装饰函数定义时立即执行,而不是在被装饰函数调用时执行。这意味着装饰器函数体内的代码会在模块加载时运行。

示例代码:


    
    
    
  @simple_decorator
def another_function():
    """另一个被简单装饰器装饰的函数"""
    print("Inside another_function")

print("another_function is defined, but not called yet.")
another_function()

被装饰函数的元信息保存(functools.wraps

当一个函数被装饰后,它的元信息(如函数名 __name__、文档字符串 __doc__、模块 __module__ 等)会丢失,变成包装器函数的元信息。functools.wraps 装饰器可以帮助我们保留原函数的元信息

示例代码:


    
    
    
  def logging_decorator(func):
    """一个用于日志记录的装饰器"""
    @functools.wraps(func) # 保留原函数的元信息
    def wrapper_log(*args, **kwargs):
        print(f"LOG: Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        print(f"LOG: {func.__name__} returned: {result}")
        return result
    return wrapper_log

@logging_decorator
def add(a, b):
    """执行加法运算的函数"""
    return a + b

print(f"add(1, 2) = {add(1, 2)}")
print(f"Function name: {add.__name__}") # 应该输出 'add'
print(f"Function doc: {add.__doc__}")   # 应该输出 '执行加法运算的函数'

装饰器的嵌套使用

一个函数可以被多个装饰器装饰。装饰器的执行顺序是从最靠近函数的装饰器开始,向外层依次执行。在调用被装饰函数时,最外层的装饰器逻辑最先执行,最内层的装饰器逻辑最后执行。

示例代码:


    
    
    
  def decorator_a(func):
    """装饰器A"""
    @functools.wraps(func)
    def wrapper_a(*args, **kwargs):
        print("--- Before A ---")
        result = func(*args, **kwargs)
        print("--- After A ---")
        return result
    return wrapper_a

def decorator_b(func):
    """装饰器B"""
    @functools.wraps(func)
    def wrapper_b(*args, **kwargs):
        print("--- Before B ---")
        result = func(*args, **kwargs)
        print("--- After B ---")
        return result
    return wrapper_b

@decorator_a
@decorator_b
def decorated_function():
    """一个被多个装饰器装饰的函数"""
    print("Inside decorated_function")

decorated_function()

3. 带参数的装饰器

装饰器工厂函数

带参数的装饰器需要一个额外的外层函数来接收参数,这个外层函数被称为装饰器工厂函数。它返回一个真正的装饰器函数。

示例代码:


    
    
    
  def repeat(num_times):
    """一个带参数的装饰器,用于重复执行函数"""
    def decorator_repeat(func):
        @functools.wraps(func)
        def wrapper_repeat(*args, **kwargs):
            for _ in range(num_times):
                print(f"Repeating {func.__name__}...")
                func(*args, **kwargs)
        return wrapper_repeat
    return decorator_repeat

@repeat(num_times=3)
def say_hi():
    """重复打招呼的函数"""
    print("Hi!")

say_hi()

@repeat(num_times=2)
def greet_person(name):
    """重复问候一个人的函数"""
    print(f"Hello, {name}!")

greet_person("Charlie")

三层嵌套结构的理解

带参数的装饰器通常具有三层嵌套结构:

  1. 1. 外层函数 (repeat): 接收装饰器参数 (num_times)。

  2. 2. 中间函数 (decorator_repeat): 接收被装饰函数 (func)。

  3. 3. 内层函数 (wrapper_repeat): 接收被装饰函数的参数 (*args, **kwargs),并执行原函数。

参数化装饰器的实际应用

参数化装饰器在实际应用中非常有用,例如可以根据参数指定所需的权限、配置重试次数等。

示例代码 (权限验证):


    
    
    
  class User:
    """模拟用户类"""
    def __init__(self, name, role):
        self.name = name
        self.role = role

    def get(self, key):
        if key == "name":
            return self.name
        elif key == "role":
            return self.role
        return None

def require_role(role):
    """一个权限验证装饰器,要求用户具有特定角色"""
    def decorator_require_role(func):
        @functools.wraps(func)
        def wrapper_require_role(user, *args, **kwargs):
            if user.get("role") == role:
                print(f"User {user.get('name')} has role '{role}'. Access granted.")
                return func(user, *args, **kwargs)
            else:
                print(f"User {user.get('name')} does not have role '{role}'. Access denied.")
                return None
        return wrapper_require_role
    return decorator_require_role

admin_user = User("Admin", "admin")
guest_user = User("Guest", "guest")

@require_role("admin")
def delete_data(user):
    """删除数据的函数,需要admin权限"""
    print(f"{user.get('name')} is deleting data.")
    return "Data deleted"

@require_role("guest")
def view_report(user):
    """查看报告的函数,需要guest权限"""
    print(f"{user.get('name')} is viewing report.")
    return "Report data"

print(delete_data(admin_user))
print(delete_data(guest_user))
print(view_report(admin_user))
print(view_report(guest_user))

4. 类装饰器

使用类实现装饰器

类装饰器通过实现 __call__ 方法,使其实例可以像函数一样被调用。当一个类被用作装饰器时,Python 会创建一个该类的实例,然后将这个实例作为装饰器来使用。

示例代码:


    
    
    
  class ClassDecorator:
    """一个使用类实现的装饰器"""
    def __init__(self, func):
        self.func = func
        functools.update_wrapper(self, func) # 保留原函数的元信息

    def __call__(self, *args, **kwargs):
        print(f"ClassDecorator: Before calling {self.func.__name__}")
        result = self.func(*args, **kwargs)
        print(f"ClassDecorator: After calling {self.func.__name__}")
        return result

@ClassDecorator
def class_decorated_function():
    """被类装饰器装饰的函数"""
    print("Inside class_decorated_function")

class_decorated_function()

带参数的类装饰器

带参数的类装饰器需要一个 __init__ 方法来接收装饰器参数,然后 __call__ 方法接收被装饰的函数。

示例代码:


    
    
    
  class ClassDecoratorWithArgs:
    """一个带参数的类装饰器"""
    def __init__(self, prefix=""):
        self.prefix = prefix

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"ClassDecoratorWithArgs: {self.prefix} - Before calling {func.__name__}")
            result = func(*args, **kwargs)
            print(f"ClassDecoratorWithArgs: {self.prefix} - After calling {func.__name__}")
            return result
        return wrapper

@ClassDecoratorWithArgs(prefix="DEBUG")
def debug_function():
    """被带参数类装饰器装饰的函数"""
    print("Inside debug_function")

debug_function()

类装饰器 vs 函数装饰器的优缺点

优点:

  • 状态维护: 类装饰器可以更容易地维护状态(通过实例属性),这对于需要跨多次函数调用保持信息的场景非常有用。

  • 更复杂的逻辑: 可以实现更复杂的逻辑,例如在 __init__ 中进行初始化,在 __call__ 中执行装饰逻辑。

缺点:

  • 语法相对复杂: 需要理解 __init____call__ 方法,相对于函数装饰器来说,语法结构稍微复杂一些。

5. 装饰类的装饰器

装饰器应用在类上

装饰器不仅可以装饰函数,也可以装饰类。当装饰器应用于类时,它接收类对象作为参数,并返回一个新的类或修改后的类。这允许我们在类定义时修改类的行为或结构。

示例代码 (动态添加方法):


    
    
    
  def add_method(cls):
    """一个装饰类的装饰器,为类添加一个新方法"""
    def new_method(self):
        print(f"New method added to {self.__class__.__name__} instance.")
    cls.new_method = new_method # 动态添加方法
    return cls

@add_method
class MyClass:
    """一个被装饰器装饰的类"""
    def __init__(self, name):
        self.name = name

    def original_method(self):
        print(f"Original method of {self.name}")

obj = MyClass("Test")
obj.original_method()
obj.new_method() # 调用动态添加的方法

单例模式等设计模式的实现

装饰器是实现单例模式等设计模式的优雅方式。

示例代码 (单例模式):


    
    
    
  import time

def singleton(cls):
    """一个实现单例模式的装饰器"""
    instances = {}
    @functools.wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class DatabaseConnection:
    """一个单例数据库连接类"""
    def __init__(self):
        print("Creating new database connection...")
        self.connection_id = time.time()

    def get_id(self):
        return self.connection_id

db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(f"DB1 ID: {db1.get_id()}")
print(f"DB2 ID: {db2.get_id()}")
print(f"Are db1 and db2 the same instance? {db1 is db2}")

6. 内置装饰器

@property@staticmethod@classmethod

  • @property: 将类的方法转换为属性,可以直接访问而无需调用。可以定义 getter、setter 和 deleter 方法。

  • @staticmethod: 静态方法,不接收实例或类作为第一个参数。它与类或实例无关,只是逻辑上归属于类。

  • @classmethod: 类方法,接收类本身作为第一个参数(通常命名为 cls)。它可以访问类属性,但不能访问实例属性。

示例代码:


    
    
    
  class MyPropertyClass:
    """演示内置装饰器 @property, @staticmethod, @classmethod 的类"""
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        """属性的getter方法"""
        print("Getting value")
        return self._value

    @value.setter
    def value(self, new_value):
        """属性的setter方法"""
        print("Setting value")
        self._value = new_value

    @staticmethod
    def static_method():
        """静态方法,不接收实例或类作为第一个参数"""
        print("This is a static method.")

    @classmethod
    def class_method(cls):
        """类方法,接收类作为第一个参数"""
        print(f"This is a class method of {cls.__name__}.")

obj_prop = MyPropertyClass(10)
print(f"Initial value: {obj_prop.value}")
obj_prop.value = 20
print(f"New value: {obj_prop.value}")
MyPropertyClass.static_method()
obj_prop.static_method() # 也可以通过实例调用
MyPropertyClass.class_method()
obj_prop.class_method() # 也可以通过实例调用

@functools.lru_cache

lru_cache (Least Recently Used) 是一种缓存机制,用于缓存函数调用结果,以提高性能。它会记住最近的函数调用结果,当相同的参数再次出现时,直接返回缓存结果,避免重复计算。

示例代码:


    
    
    
  @functools.lru_cache(maxsize=None) # maxsize=None 表示不限制缓存大小
def fibonacci(n):
    """计算斐波那契数列的函数,使用LRU缓存"""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print("Calculating fibonacci(10) with lru_cache:")
start_time = time.perf_counter()
print(f"fibonacci(10) = {fibonacci(10)}")
end_time = time.perf_counter()
print(f"Time taken: {end_time - start_time:.6f} seconds")

print("Calculating fibonacci(10) again (should be faster due to cache):")
start_time = time.perf_counter()
print(f"fibonacci(10) = {fibonacci(10)}")
end_time = time.perf_counter()
print(f"Time taken: {end_time - start_time:.6f} seconds")

@functools.singledispatch

singledispatch 用于创建泛型函数,允许你根据函数的第一个参数的类型注册不同的实现。这在处理不同类型的数据时非常有用。

示例代码:


    
    
    
  @functools.singledispatch
def process_data(data):
    """泛型函数:处理不同类型的数据"""
    print(f"Processing generic data: {data} (type: {type(data)})")

@process_data.register(int)
def _(data: int):
    """处理整数类型的数据"""
    print(f"Processing integer data: {data * 2}")

@process_data.register(str)
def _(data: str):
    """处理字符串类型的数据"""
    print(f"Processing string data: {data.upper()}")

@process_data.register(list)
def _(data: list):
    """处理列表类型的数据"""
    print(f"Processing list data: {len(data)} items")

process_data(10)
process_data("hello")
process_data([1, 2, 3])
process_data(3.14) # 没有注册浮点数类型,会调用泛型实现

7. 常见装饰器模式

日志记录装饰器

用于在函数执行前后记录日志信息,例如函数调用、参数、返回值和执行时间。

示例代码:


    
    
    
  def log_calls(func):
    """日志记录装饰器"""
    @functools.wraps(func)
    def wrapper_log(*args, **kwargs):
        print(f"INFO: Calling {func.__name__} at {time.ctime()}")
        result = func(*args, **kwargs)
        print(f"INFO: {func.__name__} finished at {time.ctime()}")
        return result
    return wrapper_log

@log_calls
def calculate_sum(a, b):
    """计算两个数的和"""
    return a + b

print(f"Sum: {calculate_sum(5, 3)}")

性能计时装饰器

用于测量函数执行所需的时间,帮助识别性能瓶颈。

示例代码:


    
    
    
  def timing_decorator(func):
    """性能计时装饰器"""
    @functools.wraps(func)
    def wrapper_timer(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Function {func.__name__} took {run_time:.4f} seconds to execute.")
        return result
    return wrapper_timer

@timing_decorator
def long_running_task():
    """模拟一个长时间运行的任务"""
    time.sleep(1)
    print("Task completed.")

long_running_task()

权限验证装饰器

用于检查用户是否具有执行某个操作的权限。

示例代码 (已在 3. 中演示 require_role)

重试机制装饰器

用于在函数执行失败时自动重试,提高程序的健壮性。

示例代码:


    
    
    
  import threading

def retry(max_attempts=3, delay=1):
    """重试机制装饰器"""
    def decorator_retry(func):
        @functools.wraps(func)
        def wrapper_retry(*args, **kwargs):
            for attempt in range(1, max_attempts + 1):
                try:
                    print(f"Attempt {attempt} for {func.__name__}...")
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"Attempt {attempt} failed: {e}")
                    if attempt < max_attempts:
                        time.sleep(delay)
            raise Exception(f"Function {func.__name__} failed after {max_attempts} attempts.")
        return wrapper_retry
    return decorator_retry

call_count = 0
@retry(max_attempts=3, delay=0.5)
def unreliable_function():
    """一个不可靠的函数,会随机失败"""
    global call_count
    call_count += 1
    if call_count < 3:
        raise ValueError("Simulated failure")
    print("unreliable_function succeeded!")
    return "Success"

try:
    print(unreliable_function())
except Exception as e:
    print(e)

缓存装饰器

用于缓存函数调用结果,避免重复计算。

示例代码 (已在 6. 中演示 functools.lru_cache)

8. 高级主题

装饰器的链式调用顺序

当多个装饰器应用于同一个函数时,它们的执行顺序是从最靠近函数的装饰器开始,向外层依次执行。
例如:


    
    
    
  @decorator_a
@decorator_b
def my_func():
    pass

等价于 my_func = decorator_a(decorator_b(my_func))
这意味着 decorator_b 会先装饰 my_func,然后 decorator_a 装饰 decorator_b 返回的函数。
在实际调用 my_func() 时,最外层的装饰器 (decorator_a 的包装器) 逻辑最先执行,最内层的装饰器 (decorator_b 的包装器) 逻辑次之,最后才是原函数 my_func 的逻辑。

示例代码:


    
    
    
  @decorator_a # 最外层,逻辑最先执行
@decorator_b # 内层,逻辑次之
def chained_decorated_function():
    """一个链式调用装饰器的函数"""
    print("Inside chained_decorated_function")

chained_decorated_function()

保持被装饰函数的签名

functools.wraps 装饰器已经解决了这个问题,它会复制原函数的 __name__, __doc__, __module__, __annotations__ 等属性到包装器函数上。这样在使用 inspect 模块检查函数签名时,会得到原函数的签名。

示例代码:


    
    
    
  import inspect

@logging_decorator
def example_with_signature(a: int, b: str = "default") -> str:
    """一个带有类型提示和默认参数的函数"""
    return f"a={a}, b={b}"

print(f"Signature of example_with_signature: {inspect.signature(example_with_signature)}")

异步装饰器(async/await

装饰异步函数需要使用 async/await 语法。异步装饰器通常用于处理协程函数。

示例代码:


    
    
    
  import asyncio

def async_timing_decorator(func):
    """异步性能计时装饰器"""
    @functools.wraps(func)
    async def wrapper_async_timer(*args, **kwargs):
        start_time = time.perf_counter()
        result = await func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Async function {func.__name__} took {run_time:.4f} seconds to execute.")
        return result
    return wrapper_async_timer

@async_timing_decorator
async def async_task():
    """模拟一个异步任务"""
    await asyncio.sleep(0.5)
    print("Async task completed.")
    return "Async Result"

async def main_async():
    """异步主函数"""
    result = await async_task()
    print(f"Async task returned: {result}")

# 在 Jupyter Notebook 或支持 asyncio 的环境中运行
# asyncio.run(main_async())
print("Async decorator example (requires asyncio.run to execute)")

上下文管理器装饰器

使用 contextlib.contextmanager 可以将一个生成器函数转换为上下文管理器。我们也可以创建装饰器来包装上下文管理器,以便在函数执行期间提供特定的上下文环境。

示例代码:


    
    
    
  from contextlib import contextmanager

@contextmanager
def my_context_manager(name):
    """一个简单的上下文管理器"""
    print(f"Entering context: {name}")
    yield
    print(f"Exiting context: {name}")

def context_decorator(func):
    """将函数包装在上下文管理器中的装饰器"""
    @functools.wraps(func)
    def wrapper_context(*args, **kwargs):
        with my_context_manager(func.__name__):
            return func(*args, **kwargs)
    return wrapper_context

@context_decorator
def do_something_in_context():
    """在特定上下文中执行的函数"""
    print("Doing something important.")

do_something_in_context()

9. 实际应用场景

Web 框架中的路由装饰器(如 Flask、Django)

Web 框架广泛使用装饰器来定义路由、处理请求、管理会话等。

Flask 示例 (伪代码,需要安装 Flask 才能运行):


    
    
    
  # from flask import Flask
# app = Flask(__name__)
#
# @app.route("/")
# def index():
#     return "Hello, World!"
#
# @app.route("/user/<name>")
# def show_user_profile(name):
#     return f"User {name}"
#
# if __name__ == "__main__":
#     app.run(debug=True)

测试框架中的装饰器

测试框架(如 Pytest)使用装饰器来标记测试、跳过测试、参数化测试等。

Pytest 示例 (伪代码,需要安装 pytest 才能运行):


    
    
    
  # import pytest
#
# @pytest.mark.skip(reason="not implemented yet")
# def test_feature_x():
#     assert False
#
# @pytest.mark.parametrize("input, expected", [(1, 2), (2, 3)])
# def test_increment(input, expected):
#     assert input + 1 == expected

数据验证和类型检查

装饰器可以用于在函数执行前对输入参数进行验证或类型检查。

示例代码:


    
    
    
  def validate_args(func):
    """一个简单的数据验证装饰器"""
    @functools.wraps(func)
    def wrapper_validate(*args, **kwargs):
        for i, arg in enumerate(args):
            if not isinstance(arg, (int, float)):
                raise TypeError(f"Argument {i} must be a number, got {type(arg)}")
        return func(*args, **kwargs)
    return wrapper_validate

@validate_args
def divide(a, b):
    """执行除法运算的函数,参数需要是数字"""
    return a / b

try:
    print(f"divide(10, 2) = {divide(10, 2)}")
    print(f"divide(10, 'a') = {divide(10, 'a')}")
except TypeError as e:
    print(f"Error: {e}")

API 限流和鉴权

装饰器可以用于实现 API 的限流(控制调用频率)和鉴权(验证用户身份和权限)。

示例代码 (限流):


    
    
    
  import threading

def rate_limit(max_calls, period):
    """API限流装饰器"""
    call_times = []
    call_lock = threading.Lock()

    def decorator_rate_limit(func):
        @functools.wraps(func)
        def wrapper_rate_limit(*args, **kwargs):
            nonlocal call_times
            with call_lock:
                current_time = time.time()
                # 移除超出时间窗口的调用记录
                call_times = [t for t in call_times if current_time - t < period]

                if len(call_times) >= max_calls:
                    raise Exception(f"Rate limit exceeded for {func.__name__}. Max {max_calls} calls per {period} seconds.")

                call_times.append(current_time)
                print(f"API call allowed for {func.__name__}. Calls in window: {len(call_times)}")
                return func(*args, **kwargs)
        return wrapper_rate_limit
    return decorator_rate_limit

@rate_limit(max_calls=2, period=5) # 5秒内最多调用2次
def api_call(endpoint):
    """模拟API调用"""
    print(f"Calling API endpoint: {endpoint}")
    return f"Data from {endpoint}"

print("\nTesting rate limit:")
for i in range(5):
    try:
        print(api_call("/data"))
        time.sleep(1) # 每次调用间隔1秒
    except Exception as e:
        print(f"Rate limit error: {e}")

10. 最佳实践和注意事项

装饰器的性能考虑

  • • 装饰器本身会引入一些额外的开销(函数调用栈增加、闭包创建等)。

  • • 对于性能敏感的代码,应谨慎使用装饰器,或确保装饰器本身的开销很小。

  • functools.lru_cache 是一个性能优化的好例子,它通过缓存结果来避免重复计算。

调试装饰器的技巧

  • • 使用 print 语句在装饰器内部和外部打印信息,追踪执行流程。

  • • 使用 pdb 等调试工具逐步执行代码。

  • • 确保使用 functools.wraps,这样调试时函数名和文档字符串是正确的,有助于理解代码。

装饰器的可复用性设计

  • • 设计通用性强的装饰器,可以应用于多种场景,而不是为每个特定功能都编写一个装饰器。

  • • 避免在装饰器中硬编码业务逻辑,而是通过参数或配置使其可定制,增加灵活性。

  • • 保持装饰器代码简洁,专注于单一职责,一个装饰器只做一件事。

避免过度使用装饰器

  • • 装饰器虽然强大,但过度使用会增加代码的复杂性和理解难度。

  • • 如果一个功能可以通过简单函数调用或类继承实现,不一定非要使用装饰器。

  • • 保持代码清晰和可读性是首要目标,不要为了使用装饰器而使用装饰器。


代码


    
    
    
  # decorator装饰器学习实践

import functools
import time
import threading

# 1. 基础概念
print("--- 1. 基础概念 ---")
# 装饰器的定义和作用: 装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数。
# 它的主要作用是在不修改原函数代码的情况下,为函数添加额外的功能。
# 高阶函数的概念: 接收一个或多个函数作为参数,或者返回一个函数的函数。
# 函数作为一等公民的理解: 函数可以像普通变量一样被赋值、作为参数传递、作为返回值返回。
def greet(name):
    """一个简单的问候函数"""
    return f"Hello, {name}"

def wrapper(func):
    """一个高阶函数,接收并返回一个函数"""
    def inner(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return inner

wrapped_greet = wrapper(greet)
print(wrapped_greet("Alice"))

# 装饰器的语法糖 @decorator
# @wrapper 等同于 greet = wrapper(greet)
@wrapper
def say_hello(name):
    """使用装饰器语法糖的问候函数"""
    return f"Hello, {name} from say_hello"

print(say_hello("Bob"))
print("-" * 30)

# 2. 函数装饰器基础
print("--- 2. 函数装饰器基础 ---")

# 简单装饰器的实现
def simple_decorator(func):
    """一个简单的函数装饰器"""
    def wrapper_func(*args, **kwargs):
        print(f"Calling function {func.__name__}")
        result = func(*args, **kwargs)
        print(f"Function {func.__name__} finished")
        return result
    return wrapper_func

@simple_decorator
def my_function():
    """被简单装饰器装饰的函数"""
    print("Inside my_function")

my_function()

# 装饰器的执行时机
# 装饰器在被装饰函数定义时立即执行,而不是在被装饰函数调用时执行。
print("Decorator definition time vs call time:")
@simple_decorator
def another_function():
    """另一个被简单装饰器装饰的函数"""
    print("Inside another_function")

print("another_function is defined, but not called yet.")
another_function()
print("-" * 30)

# 被装饰函数的元信息保存(functools.wraps)
# 装饰器会改变被装饰函数的元信息(如函数名、文档字符串)。
# functools.wraps 可以帮助我们保留这些元信息。
def logging_decorator(func):
    """一个用于日志记录的装饰器"""
    @functools.wraps(func) # 保留原函数的元信息
    def wrapper_log(*args, **kwargs):
        print(f"LOG: Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        print(f"LOG: {func.__name__} returned: {result}")
        return result
    return wrapper_log

@logging_decorator
def add(a, b):
    """执行加法运算的函数"""
    return a + b

print(f"add(1, 2) = {add(1, 2)}")
print(f"Function name: {add.__name__}") # 应该输出 'add'
print(f"Function doc: {add.__doc__}")   # 应该输出 '执行加法运算的函数'
print("-" * 30)

# 装饰器的嵌套使用
def decorator_a(func):
    """装饰器A"""
    @functools.wraps(func)
    def wrapper_a(*args, **kwargs):
        print("--- Before A ---")
        result = func(*args, **kwargs)
        print("--- After A ---")
        return result
    return wrapper_a

def decorator_b(func):
    """装饰器B"""
    @functools.wraps(func)
    def wrapper_b(*args, **kwargs):
        print("--- Before B ---")
        result = func(*args, **kwargs)
        print("--- After B ---")
        return result
    return wrapper_b

@decorator_a
@decorator_b
def decorated_function():
    """一个被多个装饰器装饰的函数"""
    print("Inside decorated_function")

decorated_function()
print("-" * 30)

# 3. 带参数的装饰器
print("--- 3. 带参数的装饰器 ---")

# 装饰器工厂函数
# 带参数的装饰器需要一个额外的外层函数来接收参数,这个外层函数被称为装饰器工厂函数。
# 它返回一个真正的装饰器函数。
def repeat(num_times):
    """一个带参数的装饰器,用于重复执行函数"""
    def decorator_repeat(func):
        @functools.wraps(func)
        def wrapper_repeat(*args, **kwargs):
            for _ in range(num_times):
                print(f"Repeating {func.__name__}...")
                func(*args, **kwargs)
        return wrapper_repeat
    return decorator_repeat

@repeat(num_times=3)
def say_hi():
    """重复打招呼的函数"""
    print("Hi!")

say_hi()

@repeat(num_times=2)
def greet_person(name):
    """重复问候一个人的函数"""
    print(f"Hello, {name}!")

greet_person("Charlie")
print("-" * 30)

# 三层嵌套结构的理解
# 外层函数 (repeat): 接收装饰器参数 (num_times)。
# 中间函数 (decorator_repeat): 接收被装饰函数 (func)。
# 内层函数 (wrapper_repeat): 接收被装饰函数的参数 (*args, **kwargs),并执行原函数。

# 参数化装饰器的实际应用
# 例如,一个权限验证装饰器,可以根据参数指定所需的角色。
def require_role(role):
    """一个权限验证装饰器,要求用户具有特定角色"""
    def decorator_require_role(func):
        @functools.wraps(func)
        def wrapper_require_role(user, *args, **kwargs):
            if user.get("role") == role:
                print(f"User {user.get('name')} has role '{role}'. Access granted.")
                return func(user, *args, **kwargs)
            else:
                print(f"User {user.get('name')} does not have role '{role}'. Access denied.")
                return None
        return wrapper_require_role
    return decorator_require_role

class User:
    """模拟用户类"""
    def __init__(self, name, role):
        self.name = name
        self.role = role

    def get(self, key):
        if key == "name":
            return self.name
        elif key == "role":
            return self.role
        return None

admin_user = User("Admin", "admin")
guest_user = User("Guest", "guest")

@require_role("admin")
def delete_data(user):
    """删除数据的函数,需要admin权限"""
    print(f"{user.get('name')} is deleting data.")
    return "Data deleted"

@require_role("guest")
def view_report(user):
    """查看报告的函数,需要guest权限"""
    print(f"{user.get('name')} is viewing report.")
    return "Report data"

print(delete_data(admin_user))
print(delete_data(guest_user))
print(view_report(admin_user))
print(view_report(guest_user))
print("-" * 30)

# 4. 类装饰器
print("--- 4. 类装饰器 ---")

# 使用类实现装饰器
# 类装饰器通过实现 __call__ 方法,使其实例可以像函数一样被调用。
class ClassDecorator:
    """一个使用类实现的装饰器"""
    def __init__(self, func):
        self.func = func
        functools.update_wrapper(self, func) # 保留原函数的元信息

    def __call__(self, *args, **kwargs):
        print(f"ClassDecorator: Before calling {self.func.__name__}")
        result = self.func(*args, **kwargs)
        print(f"ClassDecorator: After calling {self.func.__name__}")
        return result

@ClassDecorator
def class_decorated_function():
    """被类装饰器装饰的函数"""
    print("Inside class_decorated_function")

class_decorated_function()

# 带参数的类装饰器
class ClassDecoratorWithArgs:
    """一个带参数的类装饰器"""
    def __init__(self, prefix=""):
        self.prefix = prefix

    def __call__(self, func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"ClassDecoratorWithArgs: {self.prefix} - Before calling {func.__name__}")
            result = func(*args, **kwargs)
            print(f"ClassDecoratorWithArgs: {self.prefix} - After calling {func.__name__}")
            return result
        return wrapper

@ClassDecoratorWithArgs(prefix="DEBUG")
def debug_function():
    """被带参数类装饰器装饰的函数"""
    print("Inside debug_function")

debug_function()

# 类装饰器 vs 函数装饰器的优缺点
# 优点:
#   - 可以更容易地维护状态(实例属性)。
#   - 可以实现更复杂的逻辑,例如在 __init__ 中进行初始化,在 __call__ 中执行装饰逻辑。
# 缺点:
#   - 语法相对复杂,需要理解 __init__ 和 __call__ 方法。
print("-" * 30)

# 5. 装饰类的装饰器
print("--- 5. 装饰类的装饰器 ---")

# 装饰器应用在类上
# 装饰器不仅可以装饰函数,也可以装饰类。当装饰器应用于类时,它接收类对象作为参数,并返回一个新的类或修改后的类。
def add_method(cls):
    """一个装饰类的装饰器,为类添加一个新方法"""
    def new_method(self):
        print(f"New method added to {self.__class__.__name__} instance.")
    cls.new_method = new_method # 动态添加方法
    return cls

@add_method
class MyClass:
    """一个被装饰器装饰的类"""
    def __init__(self, name):
        self.name = name

    def original_method(self):
        print(f"Original method of {self.name}")

obj = MyClass("Test")
obj.original_method()
obj.new_method() # 调用动态添加的方法

# 单例模式等设计模式的实现
def singleton(cls):
    """一个实现单例模式的装饰器"""
    instances = {}
    @functools.wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class DatabaseConnection:
    """一个单例数据库连接类"""
    def __init__(self):
        print("Creating new database connection...")
        self.connection_id = time.time()

    def get_id(self):
        return self.connection_id

db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(f"DB1 ID: {db1.get_id()}")
print(f"DB2 ID: {db2.get_id()}")
print(f"Are db1 and db2 the same instance? {db1 is db2}")
print("-" * 30)

# 6. 内置装饰器
print("--- 6. 内置装饰器 ---")

# @property、@staticmethod、@classmethod
class MyPropertyClass:
    """演示内置装饰器 @property, @staticmethod, @classmethod 的类"""
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        """属性的getter方法"""
        print("Getting value")
        return self._value

    @value.setter
    def value(self, new_value):
        """属性的setter方法"""
        print("Setting value")
        self._value = new_value

    @staticmethod
    def static_method():
        """静态方法,不接收实例或类作为第一个参数"""
        print("This is a static method.")

    @classmethod
    def class_method(cls):
        """类方法,接收类作为第一个参数"""
        print(f"This is a class method of {cls.__name__}.")

obj_prop = MyPropertyClass(10)
print(f"Initial value: {obj_prop.value}")
obj_prop.value = 20
print(f"New value: {obj_prop.value}")
MyPropertyClass.static_method()
obj_prop.static_method() # 也可以通过实例调用
MyPropertyClass.class_method()
obj_prop.class_method() # 也可以通过实例调用
print("-" * 30)

# @functools.lru_cache
# LRU (Least Recently Used) 缓存,用于缓存函数调用结果,提高性能。
@functools.lru_cache(maxsize=None) # maxsize=None 表示不限制缓存大小
def fibonacci(n):
    """计算斐波那契数列的函数,使用LRU缓存"""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print("Calculating fibonacci(10) with lru_cache:")
start_time = time.perf_counter()
print(f"fibonacci(10) = {fibonacci(10)}")
end_time = time.perf_counter()
print(f"Time taken: {end_time - start_time:.6f} seconds")

print("Calculating fibonacci(10) again (should be faster due to cache):")
start_time = time.perf_counter()
print(f"fibonacci(10) = {fibonacci(10)}")
end_time = time.perf_counter()
print(f"Time taken: {end_time - start_time:.6f} seconds")
print("-" * 30)

# @functools.singledispatch
# 用于创建泛型函数,根据第一个参数的类型注册不同的实现。
@functools.singledispatch
def process_data(data):
    """泛型函数:处理不同类型的数据"""
    print(f"Processing generic data: {data} (type: {type(data)})")

@process_data.register(int)
def _(data: int):
    """处理整数类型的数据"""
    print(f"Processing integer data: {data * 2}")

@process_data.register(str)
def _(data: str):
    """处理字符串类型的数据"""
    print(f"Processing string data: {data.upper()}")

@process_data.register(list)
def _(data: list):
    """处理列表类型的数据"""
    print(f"Processing list data: {len(data)} items")

process_data(10)
process_data("hello")
process_data([1, 2, 3])
process_data(3.14) # 没有注册浮点数类型,会调用泛型实现
print("-" * 30)

# 7. 常见装饰器模式
print("--- 7. 常见装饰器模式 ---")

# 日志记录装饰器
def log_calls(func):
    """日志记录装饰器"""
    @functools.wraps(func)
    def wrapper_log(*args, **kwargs):
        print(f"INFO: Calling {func.__name__} at {time.ctime()}")
        result = func(*args, **kwargs)
        print(f"INFO: {func.__name__} finished at {time.ctime()}")
        return result
    return wrapper_log

@log_calls
def calculate_sum(a, b):
    """计算两个数的和"""
    return a + b

print(f"Sum: {calculate_sum(5, 3)}")

# 性能计时装饰器
def timing_decorator(func):
    """性能计时装饰器"""
    @functools.wraps(func)
    def wrapper_timer(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Function {func.__name__} took {run_time:.4f} seconds to execute.")
        return result
    return wrapper_timer

@timing_decorator
def long_running_task():
    """模拟一个长时间运行的任务"""
    time.sleep(1)
    print("Task completed.")

long_running_task()

# 权限验证装饰器 (已在 3. 中演示)

# 重试机制装饰器
def retry(max_attempts=3, delay=1):
    """重试机制装饰器"""
    def decorator_retry(func):
        @functools.wraps(func)
        def wrapper_retry(*args, **kwargs):
            for attempt in range(1, max_attempts + 1):
                try:
                    print(f"Attempt {attempt} for {func.__name__}...")
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"Attempt {attempt} failed: {e}")
                    if attempt < max_attempts:
                        time.sleep(delay)
            raise Exception(f"Function {func.__name__} failed after {max_attempts} attempts.")
        return wrapper_retry
    return decorator_retry

call_count = 0
@retry(max_attempts=3, delay=0.5)
def unreliable_function():
    """一个不可靠的函数,会随机失败"""
    global call_count
    call_count += 1
    if call_count < 3:
        raise ValueError("Simulated failure")
    print("unreliable_function succeeded!")
    return "Success"

try:
    print(unreliable_function())
except Exception as e:
    print(e)

# 缓存装饰器 (已在 6. 中演示 functools.lru_cache)
print("-" * 30)

# 8. 高级主题
print("--- 8. 高级主题 ---")

# 装饰器的链式调用顺序
# 多个装饰器应用于同一个函数时,它们的执行顺序是从最靠近函数的装饰器开始,向外层依次执行。
# 即 @decorator_a 在 @decorator_b 之前,那么 decorator_b 会先装饰函数,然后 decorator_a 装饰 decorator_b 返回的函数。
# 实际调用时,最外层的装饰器逻辑最先执行,最内层的装饰器逻辑最后执行。
@decorator_a # 最外层,逻辑最先执行
@decorator_b # 内层,逻辑次之
def chained_decorated_function():
    """一个链式调用装饰器的函数"""
    print("Inside chained_decorated_function")

chained_decorated_function()
print("-" * 30)

# 保持被装饰函数的签名
# functools.wraps 已经解决了这个问题,它会复制原函数的 __name__, __doc__, __module__, __annotations__ 等属性。
# 这样在使用 inspect 模块检查函数签名时,会得到原函数的签名。
import inspect

@logging_decorator
def example_with_signature(a: int, b: str = "default") -> str:
    """一个带有类型提示和默认参数的函数"""
    return f"a={a}, b={b}"

print(f"Signature of example_with_signature: {inspect.signature(example_with_signature)}")
print("-" * 30)

# 异步装饰器(async/await)
# 装饰异步函数需要使用 async/await 语法。
import asyncio

def async_timing_decorator(func):
    """异步性能计时装饰器"""
    @functools.wraps(func)
    async def wrapper_async_timer(*args, **kwargs):
        start_time = time.perf_counter()
        result = await func(*args, **kwargs)
        end_time = time.perf_counter()
        run_time = end_time - start_time
        print(f"Async function {func.__name__} took {run_time:.4f} seconds to execute.")
        return result
    return wrapper_async_timer

@async_timing_decorator
async def async_task():
    """模拟一个异步任务"""
    await asyncio.sleep(0.5)
    print("Async task completed.")
    return "Async Result"

async def main_async():
    """异步主函数"""
    result = await async_task()
    print(f"Async task returned: {result}")

# 在 Jupyter Notebook 或支持 asyncio 的环境中运行
# asyncio.run(main_async())
print("Async decorator example (requires asyncio.run to execute)")
print("-" * 30)

# 上下文管理器装饰器
# 使用 contextlib.contextmanager 可以将一个生成器函数转换为上下文管理器。
# 也可以创建装饰器来包装上下文管理器。
from contextlib import contextmanager

@contextmanager
def my_context_manager(name):
    """一个简单的上下文管理器"""
    print(f"Entering context: {name}")
    yield
    print(f"Exiting context: {name}")

def context_decorator(func):
    """将函数包装在上下文管理器中的装饰器"""
    @functools.wraps(func)
    def wrapper_context(*args, **kwargs):
        with my_context_manager(func.__name__):
            return func(*args, **kwargs)
    return wrapper_context

@context_decorator
def do_something_in_context():
    """在特定上下文中执行的函数"""
    print("Doing something important.")

do_something_in_context()
print("-" * 30)

# 9. 实际应用场景
print("--- 9. 实际应用场景 ---")

# Web框架中的路由装饰器(如Flask、Django)
# Flask 示例 (伪代码,需要安装 Flask 才能运行)
# from flask import Flask
# app = Flask(__name__)
#
# @app.route("/")
# def index():
#     return "Hello, World!"
#
# @app.route("/user/<name>")
# def show_user_profile(name):
#     return f"User {name}"
#
# if __name__ == "__main__":
#     app.run(debug=True)
print("Web框架中的路由装饰器 (Flask 示例):")
print("  @app.route('/')")
print("  def index():")
print("      return 'Hello, World!'")
print("  (此示例需要安装Flask才能运行)")

# 测试框架中的装饰器 (如 pytest.mark)
# Pytest 示例 (伪代码,需要安装 pytest 才能运行)
# import pytest
#
# @pytest.mark.skip(reason="not implemented yet")
# def test_feature_x():
#     assert False
#
# @pytest.mark.parametrize("input, expected", [(1, 2), (2, 3)])
# def test_increment(input, expected):
#     assert input + 1 == expected
print("测试框架中的装饰器 (Pytest 示例):")
print("  @pytest.mark.skip(reason='not implemented yet')")
print("  def test_feature_x():")
print("      pass")
print("  (此示例需要安装pytest才能运行)")

# 数据验证和类型检查
def validate_args(func):
    """一个简单的数据验证装饰器"""
    @functools.wraps(func)
    def wrapper_validate(*args, **kwargs):
        for i, arg in enumerate(args):
            if not isinstance(arg, (int, float)):
                raise TypeError(f"Argument {i} must be a number, got {type(arg)}")
        return func(*args, **kwargs)
    return wrapper_validate

@validate_args
def divide(a, b):
    """执行除法运算的函数,参数需要是数字"""
    return a / b

try:
    print(f"divide(10, 2) = {divide(10, 2)}")
    print(f"divide(10, 'a') = {divide(10, 'a')}")
except TypeError as e:
    print(f"Error: {e}")

# API限流和鉴权 (鉴权已在 3. 中演示)
# 限流示例 (使用一个简单的计数器,实际应用会更复杂)
def rate_limit(max_calls, period):
    """API限流装饰器"""
    call_times = []
    call_lock = threading.Lock()

    def decorator_rate_limit(func):
        @functools.wraps(func)
        def wrapper_rate_limit(*args, **kwargs):
            nonlocal call_times
            with call_lock:
                current_time = time.time()
                # 移除超出时间窗口的调用记录
                call_times = [t for t in call_times if current_time - t < period]

                if len(call_times) >= max_calls:
                    raise Exception(f"Rate limit exceeded for {func.__name__}. Max {max_calls} calls per {period} seconds.")

                call_times.append(current_time)
                print(f"API call allowed for {func.__name__}. Calls in window: {len(call_times)}")
                return func(*args, **kwargs)
        return wrapper_rate_limit
    return decorator_rate_limit

@rate_limit(max_calls=2, period=5) # 5秒内最多调用2次
def api_call(endpoint):
    """模拟API调用"""
    print(f"Calling API endpoint: {endpoint}")
    return f"Data from {endpoint}"

print("\nTesting rate limit:")
for i in range(5):
    try:
        print(api_call("/data"))
        time.sleep(1) # 每次调用间隔1秒
    except Exception as e:
        print(f"Rate limit error: {e}")
print("-" * 30)

# 10. 最佳实践和注意事项
print("--- 10. 最佳实践和注意事项 ---")

# 装饰器的性能考虑
# 装饰器本身会引入一些额外的开销(函数调用栈增加、闭包创建等)。
# 对于性能敏感的代码,应谨慎使用装饰器,或确保装饰器本身的开销很小。
# functools.lru_cache 是一个性能优化的好例子。

# 调试装饰器的技巧
#   - 使用 print 语句在装饰器内部和外部打印信息,追踪执行流程。
#   - 使用 pdb 等调试工具逐步执行代码。
#   - 确保使用 functools.wraps,这样调试时函数名和文档字符串是正确的。

# 装饰器的可复用性设计
#   - 设计通用性强的装饰器,可以应用于多种场景。
#   - 避免在装饰器中硬编码业务逻辑,而是通过参数或配置使其可定制。
#   - 保持装饰器代码简洁,专注于单一职责。

# 避免过度使用装饰器
#   - 装饰器虽然强大,但过度使用会增加代码的复杂性和理解难度。
#   - 如果一个功能可以通过简单函数调用或类继承实现,不一定非要使用装饰器。
#   - 保持代码清晰和可读性是首要目标。

print("\nPython装饰器学习教程结束。")

"""
--- 1. 基础概念 ---
Before function call
After function call
Hello, Alice
Before function call
After function call
Hello, Bob from say_hello
------------------------------
--- 2. 函数装饰器基础 ---
Calling function my_function
Inside my_function
Function my_function finished
Decorator definition time vs call time:
another_function is defined, but not called yet.
Calling function another_function
Inside another_function
Function another_function finished
------------------------------
LOG: Calling add with args: (1, 2), kwargs: {}
LOG: add returned: 3
add(1, 2) = 3
Function name: add
Function doc: 执行加法运算的函数
------------------------------
--- Before A ---
--- Before B ---
Inside decorated_function
--- After B ---
--- After A ---
------------------------------
--- 3. 带参数的装饰器 ---
Repeating say_hi...
Hi!
Repeating say_hi...
Hi!
Repeating say_hi...
Hi!
Repeating greet_person...
Hello, Charlie!
Repeating greet_person...
Hello, Charlie!
------------------------------
User Admin has role 'admin'. Access granted.
Admin is deleting data.
Data deleted
User Guest does not have role 'admin'. Access denied.
None
User Admin does not have role 'guest'. Access denied.
None
User Guest has role 'guest'. Access granted.
Guest is viewing report.
Report data
------------------------------
--- 4. 类装饰器 ---
ClassDecorator: Before calling class_decorated_function
Inside class_decorated_function
ClassDecorator: After calling class_decorated_function
ClassDecoratorWithArgs: DEBUG - Before calling debug_function
Inside debug_function
ClassDecoratorWithArgs: DEBUG - After calling debug_function
------------------------------
--- 5. 装饰类的装饰器 ---
Original method of Test
New method added to MyClass instance.
Creating new database connection...
DB1 ID: 1759024892.4037309
DB2 ID: 1759024892.4037309
Are db1 and db2 the same instance? True
------------------------------
--- 6. 内置装饰器 ---
Getting value
Initial value: 10
Setting value
Getting value
New value: 20
This is a static method.
This is a static method.
This is a class method of MyPropertyClass.
This is a class method of MyPropertyClass.
------------------------------
Calculating fibonacci(10) with lru_cache:
fibonacci(10) = 55
Time taken: 0.000003 seconds
Calculating fibonacci(10) again (should be faster due to cache):
fibonacci(10) = 55
Time taken: 0.000000 seconds
------------------------------
Processing integer data: 20
Processing string data: HELLO
Processing list data: 3 items
Processing generic data: 3.14 (type: &lt;class 'float'&gt;)
------------------------------
--- 7. 常见装饰器模式 ---
INFO: Calling calculate_sum at Sun Sep 28 10:01:32 2025
INFO: calculate_sum finished at Sun Sep 28 10:01:32 2025
Sum: 8
Task completed.
Function long_running_task took 1.0051 seconds to execute.
Attempt 1 for unreliable_function...
Attempt 1 failed: Simulated failure
Attempt 2 for unreliable_function...
Attempt 2 failed: Simulated failure
Attempt 3 for unreliable_function...
unreliable_function succeeded!
Success
------------------------------
--- 8. 高级主题 ---
--- Before A ---
--- Before B ---
Inside chained_decorated_function
--- After B ---
--- After A ---
------------------------------
Signature of example_with_signature: (a: int, b: str = 'default') -&gt; str
------------------------------
Async decorator example (requires asyncio.run to execute)
------------------------------
Entering context: do_something_in_context
Doing something important.
Exiting context: do_something_in_context
------------------------------
--- 9. 实际应用场景 ---
Web框架中的路由装饰器 (Flask 示例):
  @app.route('/')
  def index():
      return 'Hello, World!'
  (此示例需要安装Flask才能运行)
测试框架中的装饰器 (Pytest 示例):
  @pytest.mark.skip(reason='not implemented yet')
  def test_feature_x():
      pass
  (此示例需要安装pytest才能运行)
divide(10, 2) = 5.0
Error: Argument 1 must be a number, got &lt;class 'str'&gt;

Testing rate limit:
API call allowed for api_call. Calls in window: 1
Calling API endpoint: /data
Data from /data
API call allowed for api_call. Calls in window: 2
Calling API endpoint: /data
Data from /data
Rate limit error: Rate limit exceeded for api_call. Max 2 calls per 5 seconds.
Rate limit error: Rate limit exceeded for api_call. Max 2 calls per 5 seconds.
Rate limit error: Rate limit exceeded for api_call. Max 2 calls per 5 seconds.
------------------------------
--- 10. 最佳实践和注意事项 ---

Python装饰器学习教程结束.
"""

 

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区