Python 装饰器全攻略:从入门到精通的趣味之旅

Python 装饰器全攻略:从入门到精通的趣味之旅


内容简介

本系列文章是为 Python3 学习者精心设计的一套全面、实用的学习指南,旨在帮助读者从基础入门到项目实战,全面提升编程能力。文章结构由 5 个版块组成,内容层层递进,逻辑清晰。

  1. 基础速通n 个浓缩提炼的核心知识点,夯实编程基础;
  2. 经典范例10 个贴近实际的应用场景,深入理解 Python3 的编程技巧和应用方法;
  3. 避坑宝典10 个典型错误解析,提供解决方案,帮助读者避免常见的编程陷阱;
  4. 水平考试10 道测试题目,检验学习成果,附有标准答案,以便自我评估;
  5. 实战案例3 个迷你项目开发,带领读者从需求分析到代码实现,掌握项目开发的完整流程。

无论你是 Python3 初学者,还是希望提升实战能力的开发者,本系列文章都能为你提供清晰的学习路径和实用的编程技巧,助你快速成长为 Python3 编程高手。


阅读建议

  • 初学者:建议从 “基础速通” 开始,系统学习 Python3 的基础知识,然后通过 “经典范例”“避坑宝典” 加深理解,最后通过 “水平考试”“实战案例” 巩固所学内容;
  • 有经验的开发者:可以直接跳转到 “经典范例”“避坑宝典”,快速掌握 Python3 的高级应用技巧和常见错误处理方法,然后通过 “实战案例” 提升项目开发能力;
  • 选择性学习:如果读者对某个特定主题感兴趣,可以直接选择相应版块学习。各版块内容既相互独立又逻辑关联,方便读者根据自身需求灵活选择;
  • 测试与巩固:完成每个版块的学习后,建议通过 “水平考试” 检验学习效果,并通过 “实战案例” 将理论知识转化为实际技能;
  • 项目实战优先:如果你更倾向于实战学习,可以直接从 “实战案例” 入手,边做边学,遇到问题再回溯相关知识点。

一、基础速通

Python的装饰器(Decorator)是一种用于修改或扩展函数或方法行为的工具。它本质上是一个函数,接受一个函数作为参数,并返回一个新的函数。装饰器通常用于在不修改原函数代码的情况下,增加额外的功能。

装饰器的作用

  • 代码复用:可以将通用的功能(如日志记录、权限检查、性能测试等)封装在装饰器中,避免重复代码。
  • 动态扩展功能:在不改变原函数的情况下,动态地为函数添加新功能。
  • 简化代码:通过装饰器,可以将与核心逻辑无关的代码分离出来,使代码更清晰。

装饰器的基本语法

装饰器使用 @ 符号,放在函数定义的上方。例如:

@decorator
def function():
    pass

这等价于:

def function():
    pass
function = decorator(function)

示例

1. 简单的装饰器

以下是一个简单的装饰器示例,用于打印函数的执行时间:

import time

def timer_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

@timer_decorator
def example_function(n):
    time.sleep(n)
    print("函数执行完毕")

example_function(2)

输出:

函数执行完毕
example_function 执行时间: 2.0023秒
2. 带参数的装饰器

如果需要装饰器本身接受参数,可以再嵌套一层函数:

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

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

say_hello()

输出:

Hello!
Hello!
Hello!
3. 类装饰器

装饰器也可以是类,只要实现 __call__ 方法即可:

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.call_count = 0

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

@CountCalls
def greet():
    print("Hello, World!")

greet()
greet()

输出:

函数 greet 被调用了 1 次
Hello, World!
函数 greet 被调用了 2 次
Hello, World!

小结

装饰器是Python中非常强大的工具,可以用于日志记录、权限验证、性能测试、缓存等场景。通过装饰器,可以保持代码的简洁性和可维护性。


二、经典范例

以下是 10 个装饰器应用的经典范例:

1. 日志记录

记录函数的调用信息。

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}, 参数: {args}, {kwargs}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 执行完毕")
        return result
    return wrapper

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

print(add(3, 5))

输出:

调用函数: add, 参数: (3, 5), {}
函数 add 执行完毕
8

说明: 记录函数的调用和参数,方便调试和追踪。


2. 性能测试

测量函数的执行时间。

import time

def timer_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

@timer_decorator
def slow_function():
    time.sleep(2)

slow_function()

输出:

slow_function 执行时间: 2.0023秒

说明: 用于测试函数的性能,找出耗时操作。


3. 权限验证

检查用户是否有权限调用函数。

def auth_decorator(func):
    def wrapper(*args, **kwargs):
        user = kwargs.get("user", "guest")
        if user == "admin":
            return func(*args, **kwargs)
        else:
            return "权限不足"
    return wrapper

@auth_decorator
def delete_file(user):
    return "文件已删除"

print(delete_file(user="admin"))
print(delete_file(user="guest"))

输出:

文件已删除
权限不足

说明: 用于限制某些功能的访问权限。


4. 缓存结果

缓存函数的返回值,避免重复计算。

def cache_decorator(func):
    cache = {}
    def wrapper(*args):
        if args in cache:
            print("从缓存中获取结果")
            return cache[args]
        result = func(*args)
        cache[args] = result
        return result
    return wrapper

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

print(fibonacci(10))
print(fibonacci(10))

输出:

55
从缓存中获取结果
55

说明: 适用于计算密集型函数,提升性能。


5. 重试机制

在函数失败时自动重试。

import random

def retry_decorator(max_retries=3):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"重试 {i+1}/{max_retries}: {e}")
            raise Exception("重试次数用尽")
        return wrapper
    return decorator

@retry_decorator(max_retries=3)
def unstable_function():
    if random.random() < 0.5:
        raise Exception("随机失败")
    return "成功"

print(unstable_function())

输出:

重试 1/3: 随机失败
成功

说明: 用于处理可能失败的操作,如网络请求。


6. 单例模式

确保一个类只有一个实例。

def singleton_decorator(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper

@singleton_decorator
class Database:
    def __init__(self):
        print("数据库连接已创建")

db1 = Database()
db2 = Database()
print(db1 is db2)

输出:

数据库连接已创建
True

说明: 用于确保全局只有一个实例。


7. 输入验证

验证函数的输入参数。

def validate_input(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, int):
                raise ValueError("参数必须是整数")
        return func(*args, **kwargs)
    return wrapper

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

print(add(3, 5))
# print(add(3, "5"))  # 会抛出 ValueError

输出:

8

说明: 确保函数输入符合预期。


8. 限制调用频率

限制函数的调用频率。

import time

def rate_limit_decorator(max_calls, period):
    def decorator(func):
        calls = []
        def wrapper(*args, **kwargs):
            now = time.time()
            calls.append(now)
            calls[:] = [call for call in calls if now - call < period]
            if len(calls) > max_calls:
                raise Exception("调用频率过高")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@rate_limit_decorator(max_calls=2, period=5)
def api_call():
    return "API 调用成功"

print(api_call())
print(api_call())
# print(api_call())  # 会抛出异常

输出:

API 调用成功
API 调用成功

说明: 用于限制 API 或资源的访问频率。


9. 事务管理

确保函数在事务中执行。

def transaction_decorator(func):
    def wrapper(*args, **kwargs):
        print("事务开始")
        try:
            result = func(*args, **kwargs)
            print("事务提交")
            return result
        except Exception as e:
            print("事务回滚")
            raise e
    return wrapper

@transaction_decorator
def transfer_money():
    print("转账操作")

transfer_money()

输出:

事务开始
转账操作
事务提交

说明: 用于数据库操作或需要事务管理的场景。


10. 函数注册

将函数注册到某个集合中。

functions = []

def register_decorator(func):
    functions.append(func)
    return func

@register_decorator
def func1():
    print("函数 1")

@register_decorator
def func2():
    print("函数 2")

for func in functions:
    func()

输出:

函数 1
函数 2

说明: 用于插件系统或事件驱动编程。

小结

以上是 10 个经典的使用场景,涵盖了装饰器的多种用途。每个示例都附有测试案例和执行结果,方便理解和使用。


三、避坑宝典

在编写或使用 Python 装饰器时,可能会遇到一些典型的错误。以下是 10 种常见错误,分析出错原因并提供纠正方法,同时通过代码示例进行演示和说明。

1. 忘记调用被装饰的函数

错误原因:在装饰器中忘记调用被装饰的函数。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        # 忘记调用 func()
    return wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑

纠正方法:确保在装饰器中调用被装饰的函数。

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 调用被装饰的函数
    return wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

2. 装饰器未返回包装函数

错误原因:装饰器没有返回包装函数。

错误代码:

def decorator(func):
    print("装饰器逻辑")
    # 忘记返回 wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
TypeError: 'NoneType' object is not callable

纠正方法:确保装饰器返回包装函数。

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper  # 返回 wrapper

@decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

3. 未正确处理函数参数

错误原因:装饰器未正确处理被装饰函数的参数。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未传递参数
    return wrapper

@decorator
def my_function(a, b):
    print(f"a + b = {a + b}")

my_function(1, 2)

输出:

TypeError: wrapper() takes 0 positional arguments but 2 were given

纠正方法:使用 *args**kwargs 传递参数。

正确代码:

def decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        func(*args, **kwargs)  # 正确传递参数
    return wrapper

@decorator
def my_function(a, b):
    print(f"a + b = {a + b}")

my_function(1, 2)

输出:

装饰器逻辑
a + b = 3

4. 装饰器破坏了原函数的元信息

错误原因:装饰器覆盖了原函数的 __name____doc__ 等元信息。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

@decorator
def my_function():
    """这是一个示例函数"""
    print("函数逻辑")

print(my_function.__name__)  # 输出 wrapper
print(my_function.__doc__)   # 输出 None

输出:

wrapper
None

纠正方法:使用 functools.wraps 保留元信息。

正确代码:

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

@decorator
def my_function():
    """这是一个示例函数"""
    print("函数逻辑")

print(my_function.__name__)  # 输出 my_function
print(my_function.__doc__)   # 输出 这是一个示例函数

输出:

my_function
这是一个示例函数

5. 装饰器嵌套顺序错误

错误原因:多个装饰器的嵌套顺序错误,导致逻辑混乱。

错误代码:

def decorator1(func):
    def wrapper():
        print("装饰器 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("装饰器 2")
        func()
    return wrapper

@decorator1
@decorator2
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器 1
装饰器 2
函数逻辑

纠正方法:调整装饰器的嵌套顺序。

正确代码:

@decorator2
@decorator1
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器 2
装饰器 1
函数逻辑

6. 装饰器未正确处理返回值

错误原因:装饰器未返回被装饰函数的返回值。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未返回 func() 的结果
    return wrapper

@decorator
def my_function():
    return "函数返回值"

print(my_function())

输出:

装饰器逻辑
None

纠正方法:返回被装饰函数的结果。

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        return func()  # 返回 func() 的结果
    return wrapper

@decorator
def my_function():
    return "函数返回值"

print(my_function())

输出:

装饰器逻辑
函数返回值

7. 装饰器未正确处理异常

错误原因:装饰器未正确处理被装饰函数抛出的异常。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未捕获异常
    return wrapper

@decorator
def my_function():
    raise ValueError("函数出错")

my_function()

输出:

装饰器逻辑
ValueError: 函数出错

纠正方法:捕获并处理异常。

正确代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        try:
            func()
        except ValueError as e:
            print(f"捕获异常: {e}")
    return wrapper

@decorator
def my_function():
    raise ValueError("函数出错")

my_function()

输出:

装饰器逻辑
捕获异常: 函数出错

8. 装饰器未正确处理类方法

错误原因:装饰器未正确处理类方法的 self 参数。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()  # 未传递 self
    return wrapper

class MyClass:
    @decorator
    def my_method(self):
        print("方法逻辑")

obj = MyClass()
obj.my_method()

输出:

TypeError: wrapper() takes 0 positional arguments but 1 was given

纠正方法:使用 *args**kwargs 传递 self

正确代码:

def decorator(func):
    def wrapper(*args, **kwargs):
        print("装饰器逻辑")
        func(*args, **kwargs)
    return wrapper

class MyClass:
    @decorator
    def my_method(self):
        print("方法逻辑")

obj = MyClass()
obj.my_method()

输出:

装饰器逻辑
方法逻辑

9. 装饰器未正确处理静态方法

错误原因:装饰器未正确处理静态方法的特性。

错误代码:

def decorator(func):
    def wrapper():
        print("装饰器逻辑")
        func()
    return wrapper

class MyClass:
    @decorator
    @staticmethod
    def my_method():
        print("静态方法逻辑")

MyClass.my_method()

输出:

TypeError: 'staticmethod' object is not callable

纠正方法:将装饰器放在 @staticmethod 上方。

正确代码:

class MyClass:
    @staticmethod
    @decorator
    def my_method():
        print("静态方法逻辑")

MyClass.my_method()

输出:

装饰器逻辑
静态方法逻辑

10. 装饰器未正确处理类装饰器

错误原因:类装饰器未实现 __call__ 方法。

错误代码:

class Decorator:
    def __init__(self, func):
        self.func = func

@Decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

TypeError: 'Decorator' object is not callable

纠正方法:实现 __call__ 方法。

正确代码:

class Decorator:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("装饰器逻辑")
        return self.func(*args, **kwargs)

@Decorator
def my_function():
    print("函数逻辑")

my_function()

输出:

装饰器逻辑
函数逻辑

四、水平考试

本试卷包含选择题 15 题、填空题 10 题和编程题 5 题,共计 30 道题,满分 100 分。每道题后附有正确答案和解析。

选择题(每题2分,共30分)

  1. 装饰器的本质是什么?
    A. 类
    B. 函数
    C. 模块
    D. 变量
    答案:B
    解析:装饰器本质上是函数,用于修改或扩展其他函数的行为。

  2. 以下哪个符号用于装饰器语法?
    A. #
    B. @
    C. $
    D. &
    答案:B
    解析@ 符号用于装饰器语法。

  3. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            print("装饰器逻辑")
            func()
        return wrapper
    
    @decorator
    def my_function():
        print("函数逻辑")
    
    my_function()
    

    A. 装饰器逻辑
    B. 函数逻辑
    C. 装饰器逻辑 函数逻辑
    D. 无输出
    答案:C
    解析:装饰器会先执行 wrapper 中的逻辑,再调用原函数。

  4. 以下哪个函数可以保留被装饰函数的元信息?
    A. functools.wraps
    B. functools.partial
    C. functools.reduce
    D. functools.lru_cache
    答案:A
    解析functools.wraps 用于保留被装饰函数的元信息。

  5. 以下代码的输出是什么?

    def decorator(func):
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs) + 1
        return wrapper
    
    @decorator
    def add(a, b):
        return a + b
    
    print(add(2, 3))
    

    A. 5
    B. 6
    C. 7
    D. 8
    答案:B
    解析:装饰器对函数结果进行了加1操作。

  6. 以下哪个场景适合使用装饰器?
    A. 计算两个数的和
    B. 记录函数的执行时间
    C. 定义类属性
    D. 创建列表
    答案:B
    解析:装饰器常用于记录日志、性能测试等场景。

  7. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            print("装饰器逻辑")
        return wrapper
    
    @decorator
    def my_function():
        print("函数逻辑")
    
    my_function()
    

    A. 装饰器逻辑
    B. 函数逻辑
    C. 装饰器逻辑 函数逻辑
    D. 无输出
    答案:A
    解析:装饰器中未调用原函数,因此只执行了 wrapper 的逻辑。

  8. 以下哪个装饰器可以缓存函数的结果?
    A. @functools.lru_cache
    B. @functools.wraps
    C. @staticmethod
    D. @property
    答案:A
    解析@functools.lru_cache 用于缓存函数的结果。

  9. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            return func().upper()
        return wrapper
    
    @decorator
    def greet():
        return "hello"
    
    print(greet())
    

    A. hello
    B. HELLO
    C. Hello
    D. 无输出
    答案:B
    解析:装饰器将函数返回值转换为大写。

  10. 以下哪个装饰器用于限制函数调用频率?
    A. @rate_limit
    B. @cache
    C. @retry
    D. @log
    答案:A
    解析@rate_limit 用于限制函数调用频率。

  11. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            return func() + " world"
        return wrapper
    
    @decorator
    def greet():
        return "hello"
    
    print(greet())
    

    A. hello
    B. world
    C. hello world
    D. 无输出
    答案:C
    解析:装饰器在函数返回值后添加了 " world"。

  12. 以下哪个装饰器用于将方法定义为类方法?
    A. @staticmethod
    B. @classmethod
    C. @property
    D. @abstractmethod
    答案:B
    解析@classmethod 用于定义类方法。

  13. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            return func() * 2
        return wrapper
    
    @decorator
    def get_value():
        return 5
    
    print(get_value())
    

    A. 5
    B. 10
    C. 25
    D. 无输出
    答案:B
    解析:装饰器将函数返回值乘以2。

  14. 以下哪个装饰器用于将方法定义为静态方法?
    A. @staticmethod
    B. @classmethod
    C. @property
    D. @abstractmethod
    答案:A
    解析@staticmethod 用于定义静态方法。

  15. 以下代码的输出是什么?

    def decorator(func):
        def wrapper():
            return func() + 10
        return wrapper
    
    @decorator
    def get_value():
        return 5
    
    print(get_value())
    

    A. 5
    B. 10
    C. 15
    D. 无输出
    答案:C
    解析:装饰器在函数返回值后加了10。


填空题(每题3分,共30分)

  1. 装饰器的本质是一个______。
    答案:函数

  2. 使用 @ 符号调用装饰器时,装饰器函数必须返回一个______。
    答案:函数

  3. functools.wraps 的作用是保留被装饰函数的______。
    答案:元信息

  4. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func() + 1
        return wrapper
    
    @decorator
    def get_value():
        return 5
    
    print(get_value())
    

    答案:6

  5. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func().upper()
        return wrapper
    
    @decorator
    def greet():
        return "hello"
    
    print(greet())
    

    答案:HELLO

  6. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func() * 2
        return wrapper
    
    @decorator
    def get_value():
        return 3
    
    print(get_value())
    

    答案:6

  7. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func() + " world"
        return wrapper
    
    @decorator
    def greet():
        return "hello"
    
    print(greet())
    

    答案:hello world

  8. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func() + 10
        return wrapper
    
    @decorator
    def get_value():
        return 5
    
    print(get_value())
    

    答案:15

  9. 以下代码的输出是______。

    def decorator(func):
        def wrapper():
            return func() + 1
        return wrapper
    
    @decorator
    def get_value():
        return 5
    
    print(get_value())
    

    答案:6

  10. 以下代码的输出是______。

    def decorator(func):
    def wrapper(*args):
        return func(*args).upper()
    return wrapper
    
    @decorator
    def greet(username):
        return "hello" + ' ' + username + '!'
    
    print(greet("roger"))
    

    答案:HELLO ROGER!


编程题(每题8分,共40分)

  1. 编写一个装饰器,记录函数的执行时间并打印。
    答案:

    import time
    
    def timer_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
    
    @timer_decorator
    def my_function():
        time.sleep(2)
    
    my_function()
    
  2. 编写一个装饰器,缓存函数的结果以避免重复计算。
    答案:

    def cache_decorator(func):
        cache = {}
        def wrapper(*args):
            if args in cache:
                return cache[args]
            result = func(*args)
            cache[args] = result
            return result
        return wrapper
    
    @cache_decorator
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-1) + fibonacci(n-2)
    
    print(fibonacci(10))
    
  3. 编写一个装饰器,限制函数的调用频率(例如每秒最多调用一次)。
    答案:

    import time
    
    def rate_limit_decorator(max_calls, period):
        calls = []
        def decorator(func):
            def wrapper(*args, **kwargs):
                now = time.time()
                calls.append(now)
                calls[:] = [call for call in calls if now - call < period]
                if len(calls) > max_calls:
                    raise Exception("调用频率过高")
                return func(*args, **kwargs)
            return wrapper
        return decorator
    
    @rate_limit_decorator(max_calls=1, period=1)
    def my_function():
        print("函数调用")
    
    my_function()
    
  4. 编写一个装饰器,实现函数的重试机制(例如失败后重试3次)。
    答案:

    import random
    
    def retry_decorator(max_retries=3):
        def decorator(func):
            def wrapper(*args, **kwargs):
                for i in range(max_retries):
                    try:
                        return func(*args, **kwargs)
                    except Exception as e:
                        print(f"重试 {i+1}/{max_retries}: {e}")
                raise Exception("重试次数用尽")
            return wrapper
        return decorator
    
    @retry_decorator(max_retries=3)
    def unstable_function():
        if random.random() < 0.5:
            raise Exception("随机失败")
        return "成功"
    
    print(unstable_function())
    
  5. 编写一个装饰器,将函数的返回值格式化为 JSON 字符串。
    答案:

    import json
    
    def json_decorator(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            return json.dumps(result)
        return wrapper
    
    @json_decorator
    def my_function():
        return {"name": "Alice", "age": 30}
    
    print(my_function())
    

总分:100分
希望这套试卷能帮助你巩固 Python 装饰器的知识!


五、实战案例

以下是 3 个使用 Python 装饰器的综合应用项目,这些项目具有新颖性、前瞻性和实用性。每个项目都包含完整的代码、解释说明、测试案例和执行结果。

项目 1:API 请求限流器

描述:实现一个装饰器,限制 API 请求的频率,防止服务器过载。

代码实现

import time

def rate_limiter(max_calls, period):
    """
    限制函数调用频率的装饰器。
    :param max_calls: 每个时间段内允许的最大调用次数。
    :param period: 时间段(秒)。
    """
    calls = []

    def decorator(func):
        def wrapper(*args, **kwargs):
            now = time.time()
            # 移除超时的调用记录
            calls[:] = [call for call in calls if now - call < period]
            if len(calls) >= max_calls:
                raise Exception("请求频率过高,请稍后再试")
            calls.append(now)
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 测试案例
@rate_limiter(max_calls=3, period=5)
def api_request():
    print("API 请求成功")

# 模拟请求
for i in range(5):
    try:
        api_request()
    except Exception as e:
        print(e)
    time.sleep(1)

执行结果

API 请求成功
API 请求成功
API 请求成功
请求频率过高,请稍后再试
请求频率过高,请稍后再试

说明:该装饰器限制每 5 秒内最多调用 3 次 API,超过限制会抛出异常。


项目 2:函数结果缓存

描述:实现一个装饰器,缓存函数的结果,避免重复计算。

代码实现

def cache_decorator(func):
    """
    缓存函数结果的装饰器。
    """
    cache = {}

    def wrapper(*args):
        if args in cache:
            print("从缓存中获取结果")
            return cache[args]
        result = func(*args)
        cache[args] = result
        return result
    return wrapper

# 测试案例
@cache_decorator
def fibonacci(n):
    """
    计算斐波那契数列。
    """
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))
print(fibonacci(10))

执行结果

55
从缓存中获取结果
55

说明:该装饰器缓存了斐波那契数列的计算结果,避免重复计算。


项目 3:异步任务重试机制

描述:实现一个装饰器,为异步任务提供重试机制。

代码实现

import asyncio
import random

def retry_decorator(max_retries=3):
    """
    为异步函数提供重试机制的装饰器。
    :param max_retries: 最大重试次数。
    """
    def decorator(func):
        async def wrapper(*args, **kwargs):
            for i in range(max_retries):
                try:
                    return await func(*args, **kwargs)
                except Exception as e:
                    print(f"重试 {i+1}/{max_retries}: {e}")
                    await asyncio.sleep(1)
            raise Exception("重试次数用尽")
        return wrapper
    return decorator

# 测试案例
@retry_decorator(max_retries=3)
async def unstable_task():
    if random.random() < 0.5:
        raise Exception("任务失败")
    return "任务成功"

async def main():
    try:
        result = await unstable_task()
        print(result)
    except Exception as e:
        print(e)

asyncio.run(main())

执行结果

重试 1/3: 任务失败
任务成功

说明:该装饰器为异步任务提供了重试机制,失败后最多重试 3 次。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值