Python 进阶 - 第十八节


📋 本节要点

知识点 说明
装饰器 增强函数功能的函数
@ 语法糖 装饰器的简洁写法
*args, **kwargs 装饰带参数的函数
wraps 保留原函数名称和文档
带参数装饰器 三层嵌套,接收参数配置
多个装饰器叠加 从上往下执行

1. 装饰器是什么?

装饰器是本身也是一个函数,可以在不修改原函数代码的前提下,给原函数添加额外功能。

1.1 基本结构

def 装饰器函数名称(func):
    def wrapper():
        # 执行原函数前的操作
        func()
        # 执行原函数后的操作
    return wrapper

1.2 不使用装饰器 vs 使用装饰器

def my_decorator(func):
    def wrapper():
        print("===开始===")
        func()
        print("===结束===")
    return wrapper

def say_hello1():
    print("你好!")

# 不使用装饰器
say_hello1()   # 你好!

# 使用装饰器
say_hello1 = my_decorator(say_hello1)
say_hello1()
# ===开始===
# 你好!
# ===结束===

2. @ 语法糖

@装饰器名称 是装饰器的简洁写法,等价于 func = decorator(func)。

@my_decorator           # 等价于 say_hello2 = my_decorator(say_hello2)
def say_hello2():
    print("你好!")

say_hello2()
# ===开始===
# 你好!
# ===结束===

3. 装饰带参数的函数

使用 *args, **kwargs 让装饰器能处理任意参数的函数:

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数 {func.__name__} 执行时间:{end - start:.4f} 秒")
        return result
    return wrapper

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

@timer_decorator
def greet(name):
    print(f"你好,{name}!")

result = add(1, 2)      # 函数 add 执行时间:0.0000 秒
greet("张三")           # 你好,张三!\n函数 greet 执行时间:0.0000 秒

4. 保留原函数信息

装饰后函数名会变成 wrapper,用 functools.wraps 修复:

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print("调用函数前")
        result = func(*args, **kwargs)
        print("调用函数后")
        return result
    return wrapper

@my_decorator
def say_hello():
    """这是 say_hello 函数的文档"""
    print("你好!")

print(say_hello.__name__)  # say_hello(而不是 wrapper)
print(say_hello.__doc__)   # 这是 say_hello 函数的文档

5. 带参数的装饰器

如果装饰器本身需要接收参数,需要再包一层函数——三层嵌套结构。

def repeat(times):
    def decorator(func):                # 接收函数
        @functools.wraps(func)
        def wrapper(*args, **kwargs):   # 增强逻辑
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def say_hello():
    print("你好!")

say_hello()  # 你好!(打印 3 次)

6. 多个装饰器叠加

多个装饰器可以叠加使用,执行顺序从上往下。

def decorator1(func):
    def wrapper(*args, **kwargs):
        print("装饰器1 - 开始")
        result = func(*args, **kwargs)
        print("装饰器1 - 结束")
        return result
    return wrapper

def decorator2(func):
    def wrapper(*args, **kwargs):
        print("装饰器2 - 开始")
        result = func(*args, **kwargs)
        print("装饰器2 - 结束")
        return result
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("你好!")

say_hello()
# 装饰器1 - 开始
# 装饰器2 - 开始
# 你好!
# 装饰器2 - 结束
# 装饰器1 - 结束

7. 实战:权限验证

import functools

def requires_auth(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        is_logged_in = False  # 模拟登录状态
        if is_logged_in:
            return func(*args, **kwargs)
        else:
            print("请先登录!")
            return None
    return wrapper

@requires_auth
def view_profile():
    print("查看个人资料")

@requires_auth
def edit_profile():
    print("编辑个人资料")

view_profile()   # 请先登录!
edit_profile()   # 请先登录!

下一节预告:生成器与迭代器