装饰器怎么写?

访客 python案例 1

本文目录导读:

  1. 目录导读
  2. 什么是装饰器?
  3. 装饰器怎么写?——三步构建法
  4. 实战场景:4个立刻能用的装饰器
  5. 进阶技巧
  6. 常见问答(Q&A)
  7. SEO与搜索引擎优化技巧

装饰器怎么写?手把手教你从零掌握Python高阶技巧

目录导读

  1. 什么是装饰器?——核心定义与生活类比
  2. 装饰器怎么写?——基础语法与三步构建法
  3. 实用场景——日志、权限、缓存、计时
  4. 进阶技巧——带参数装饰器、多个装饰器叠加
  5. 常见问答——新手最易混淆的4个问题
  6. SEO优化建议——代码演示与搜索引擎友好技巧

什么是装饰器?

定义:装饰器是一个接受函数作为参数并返回新函数(或类)的可调用对象,它允许你在不修改原函数代码的情况下,为函数添加额外功能。

生活类比: 你想给手机加一个保护壳——手机本身的功能不变(打电话、发微信),但壳子提供了防摔、美观的附加价值,装饰器就是那个“壳子”,原函数是“手机”。

核心公式

@decorator
def original_func():
    pass
# 等价于:original_func = decorator(original_func)

装饰器怎么写?——三步构建法

Step1:定义外层函数(接收原函数)

def my_decorator(func):

Step2:定义内层函数(包裹逻辑)

def wrapper(*args, **kwargs):
    # 在调用原函数前添加新功能
    print("执行前:记录日志")
    result = func(*args, **kwargs)  # 调用原函数
    # 在调用原函数后添加新功能
    print("执行后:统计耗时")
    return result

Step3:返回内层函数

return wrapper

完整示例

def timer_decorator(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 耗时 {end-start:.2f} 秒")
        return result
    return wrapper
@timer_decorator
def slow_function():
    sum([i**2 for i in range(1000000)])
slow_function()  # 输出:slow_function 耗时 0.15 秒

关键点

  • 使用*args, **kwargs确保通用性
  • 保留return result防止原函数返回值丢失
  • 可通过functools.wraps保留原函数元信息(后文详述)

实战场景:4个立刻能用的装饰器

日志记录

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"[INFO] 调用 {func.__name__}, 参数={args},{kwargs}")
        return func(*args, **kwargs)
    return wrapper

权限验证(模拟)

def require_auth(user_role):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if user_role != "admin":
                raise PermissionError("权限不足")
            return func(*args, **kwargs)
        return wrapper
    return decorator
@require_auth("admin")
def delete_user(user_id):
    print(f"删除用户 {user_id}")

缓存计算结果(性能提升)

def cache_decorator(func):
    from functools import lru_cache
    return lru_cache(maxsize=128)(func)
# 等价于:@lru_cache(maxsize=128) 写在函数上

重试机制(稳定调用)

def retry(max_attempts=3):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"第{i+1}次失败: {e}")
                    continue
            raise Exception("超过最大重试次数")
        return wrapper
    return decorator

进阶技巧

保留原函数元信息(忘记会踩坑!)

from functools import wraps
def my_decorator(func):
    @wraps(func)  # 这条是关键
    def wrapper(*args, **kwargs):
        """这是一个wrapper"""
        return func(*args, **kwargs)
    return wrapper
@my_decorator
def hello():
    """原始函数说明"""
    pass
print(hello.__name__)  # 输出:hello(如果不加@wraps,会输出wrapper)
print(hello.__doc__)   # 输出:原始函数说明

多个装饰器叠加(执行顺序从下往上)

@log_decorator
@timer_decorator
def compute():
    return 42
# 执行效果:先计时,再打印日志(因为第一个套在最外层)

类装饰器(使用call

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"调用次数: {self.count}")
        return self.func(*args, **kwargs)
@CountCalls
def say_hello():
    print("Hello!")
say_hello()  # 调用次数: 1
say_hello()  # 调用次数: 2

常见问答(Q&A)

Q1:装饰器和普通函数有什么区别?

  • 普通函数直接执行代码;装饰器是“函数工厂”,它接收函数并返回增强版函数,装饰器可以跨函数复用逻辑,而普通函数需要手动在每个目标函数内调用。

Q2:带参数和不带参数的装饰器,写法上有什么不同?

  • 不带参数:直接@decorator
  • 带参数:需要三层嵌套——外层接收参数,中层接收函数,内层包裹逻辑,例如上面的require_authretry

Q3:什么时候一定要用functools.wraps

  • 当你需要装饰后的函数保持原始函数的名称、文档字符串、参数签名时,例如在调试或生成API文档时会依赖func.__name__

Q4:装饰器能用在类的方法上吗?

  • 可以,但如果方法有self参数,wrapper需要用*args, **kwargs接收,第一个参数自动成为self,如果需要访问实例属性,直接在wrapper内使用args[0]kwargs

Q5:装饰器和闭包有什么关系?

  • 装饰器本质上就是闭包的一个应用,闭包是引用了外部变量(如func)的内函数,装饰器通过闭包“原函数并扩展其行为。

SEO与搜索引擎优化技巧

为了让这篇文章在必应和谷歌获得良好排名,已融入以下策略:含关键词**:核心词“装饰器怎么写”置于开头

  • H标签层级清晰:H1→H2→H3,符合语义化
  • 问答结构:模拟用户搜索意图(如“装饰器怎么写”“带参数装饰器”)
  • 代码块可复制:使用三段式代码高亮,提升用户体验
  • 内部链接概念:提及闭包高阶函数等关联技术名词,增加主题相关性
  • 段落长度适中:每部分100-300字,避免长段落影响移动端阅读
  • 关键词自然分布:全文出现“装饰器”约20次、“函数”约25次,密度合理

通过以上6个模块,你已经掌握了从零编写装饰器的完整流程。装饰器不是语法糖,而是函数式编程的实用工具,建议从现在开始,为你的项目添加一个日志装饰器或计时装饰器,实践是检验理解的唯一标准。

标签: 装饰器语法

抱歉,评论功能暂时关闭!