装饰器是闭包最核心、最实用的应用,你可以把它理解成给函数 “套壳”—— 不修改原函数代码,就能给原函数增加新功能(日志、计时、权限、缓存等)。


一、装饰器是什么?

        一句话:装饰器 = 一个函数 + 接收另一个函数做参数 + 返回新函数 + 不修改原函数代码 + 增加新功能

本质:装饰器就是一个闭包!


二、为什么要用装饰器?

        假如你有 100 个函数,想给它们全部加计时功能

  • 不使用装饰器:改 100 个函数
  • 使用装饰器:写 1 个装饰器,@ 一下全部搞定

        开闭原则:对修改关闭,对扩展开放


三、最简单装饰器(一步步写)

1. 原函数(不想修改它)

def say_hello():
    print("你好")

2. 写一个装饰器(闭包)

# 装饰器函数
def my_decorator(func):
    # 内部函数(真正执行新功能)
    def wrapper():
        # 新增功能
        print("函数执行前")
        func()  # 调用原函数
        # 新增功能
        print("函数执行后")
    return wrapper

3. 使用装饰器

# 方法1:手动包装
new_func = my_decorator(say_hello)
new_func()

# 方法2:语法糖 @(最常用!)
@my_decorator
def say_hello():
    print("你好")

say_hello()

输出:

函数执行前
你好
函数执行后

四、带参数的函数 + 装饰器

        原函数有参数,装饰器必须用 *args, **kwargs 通用接收!

def my_decorator(func):
    def wrapper(*args, **kwargs):  # 接收任意参数
        print("前")
        result = func(*args, **kwargs)  # 传参并接收返回值
        print("后")
        return result  # 返回原函数结果
    return wrapper

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

print(add(3, 5))  # 8

五、带返回值的函数 + 装饰器

        必须把原函数返回值返回出去,否则调用会得到 None!

result = func(...)
return result

六、最常用实战装饰器案例

1)计时装饰器(最实用)

import time

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

@timer
def test():
    time.sleep(1)

test()

2)日志装饰器

def log(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数:{func.__name__}")
        return func(*args, **kwargs)
    return wrapper

3)权限校验装饰器

def login_check(func):
    def wrapper(user):
        if not user.get("is_login"):
            return "请先登录"
        return func(user)
    return wrapper

七、带参数的装饰器(进阶)

        装饰器自己也能接收参数!需要再套一层函数

        示例:指定日志级别

def log(level):
    # 真正的装饰器
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{level}] 执行函数")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log("INFO")   # 装饰器带参数
def func():
    print("执行")

八、多个装饰器叠加

        执行顺序:从上到下装饰,从内到外执行

@decorator1
@decorator2
def func():
    ...

执行顺序:

  1. decorator1 前
  2. decorator2 前
  3. 原函数
  4. decorator2 后
  5. decorator1 后

九、保留原函数元信息(必须加!)

        不加的话,func.__name__ 会变成 wrapper,导致调试混乱。

解决方案:@functools.wraps

import functools

def my_decorator(func):
    @functools.wraps(func)  # 保留原函数名字、注释等
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

十、装饰器总结(必背)

  1. 装饰器 = 闭包
  2. 作用:不修改原函数,增加功能
  3. 语法:@装饰器名
  4. 通用模板(万能写法):
import functools

def 装饰器名(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 执行前操作
        result = func(*args, **kwargs)
        # 执行后操作
        return result
    return wrapper
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐