Python基础入门 Day116 装饰器的原理与应用进阶

101次阅读
没有评论

共计 2277 个字符,预计需要花费 6 分钟才能阅读完成。

在前面的课程中,我们已经学习了闭包的概念,并初步接触过装饰器。今天我们将更深入地探讨 Python 装饰器的工作原理、常见用途以及如何编写可复用的装饰器函数。

一、什么是装饰器
装饰器(Decorator)是 Python 中非常强大的语法糖,用于在不改变函数代码的情况下,为函数“增加新功能”。
从本质上看,装饰器是一个 返回函数的函数

举个最基本的例子:

def my_decorator(func):
    def wrapper():
        print(" 函数执行前的操作 ")
        func()
        print(" 函数执行后的操作 ")
    return wrapper

@my_decorator
def say_hello():
    print("Hello, Python!")

say_hello()

输出结果为:

函数执行前的操作
Hello, Python!
函数执行后的操作

解释:

  • @my_decorator 相当于执行 say_hello = my_decorator(say_hello)
  • 即在函数调用前后自动添加了新逻辑,实现功能扩展。

二、带参数的装饰器
上例中,装饰器只适用于无参数函数。
如果目标函数需要传参,我们可以在 wrapper 内部增加 *args**kwargs

def logger(func):
    def wrapper(*args, **kwargs):
        print(f" 开始执行函数:{func.__name__}")
        result = func(*args, **kwargs)
        print(f" 函数 {func.__name__} 执行完毕 ")
        return result
    return wrapper

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

print(add(5, 8))

输出结果为:

开始执行函数:add
函数 add 执行完毕
13

说明:
装饰器可以通用地包装各种函数,无论有无参数。

三、装饰器的嵌套使用
多个装饰器可以叠加使用,执行顺序是 从下往上(即最接近函数定义的先执行)。

def deco1(func):
    def wrapper():
        print(" 进入 deco1")
        func()
        print(" 退出 deco1")
    return wrapper

def deco2(func):
    def wrapper():
        print(" 进入 deco2")
        func()
        print(" 退出 deco2")
    return wrapper

@deco1
@deco2
def test():
    print(" 函数体执行中 ")

test()

输出顺序:

进入 deco1
进入 deco2
函数体执行中
退出 deco2
退出 deco1

说明:
先应用 @deco2,再由 @deco1 包裹,这样执行时会形成函数调用栈的层层嵌套。

四、带参数的装饰器
有时候我们希望装饰器本身也能接收参数,例如设定日志级别或启用某种模式。
此时需要用到 三层嵌套 结构:

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(n):
                print(f" 第 {i+1} 次执行 {func.__name__}")
                func(*args, **kwargs)
        return wrapper
    return decorator

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

greet()

结果:

第 1 次执行 greet
Hello!
第 2 次执行 greet
Hello!
第 3 次执行 greet
Hello!

解释:
@repeat(3) 实际上调用 repeat(3) 返回一个装饰器,然后用于修饰函数。

五、实战示例:性能监控装饰器
装饰器常被用于日志记录、性能检测、权限校验等场景。
下面编写一个统计函数执行时间的装饰器:

import time

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

@timer
def slow_operation():
    time.sleep(1)
    print(" 操作完成 ")

slow_operation()

输出示例:

操作完成
slow_operation 执行耗时:1.0012 秒

这种方法在调试或性能优化时非常有用。

六、使用 functools.wraps 保留函数元信息
如果不使用 functools.wraps,被装饰函数的元信息(如名称、文档字符串)会丢失。

from functools import wraps

def safe_wrapper(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(" 正在调用函数...")
        return func(*args, **kwargs)
    return wrapper

@safe_wrapper
def demo():
    """ 演示函数 """
    pass

print(demo.__name__)  # demo
print(demo.__doc__)   # 演示函数

说明:
@wraps(func) 可以保留原函数的元数据,这在调试和文档生成时尤为重要。

七、小结
装饰器是 Python 高级函数式编程的核心工具之一。
本节要点:

  1. 装饰器本质上是返回函数的高阶函数;
  2. 使用 @ 语法糖简化装饰过程;
  3. 可以嵌套、带参数、甚至动态控制逻辑;
  4. 使用 functools.wraps 保留函数元信息。

掌握装饰器后,你将能写出更加优雅、模块化和可复用的 Python 代码。

正文完
 0
评论(没有评论)