Python编程实战:面向对象与进阶语法——装饰器(Decorator)

在 Python 的高级语法中,装饰器(Decorator) 是一个非常强大且常用的功能。它不仅能让代码更简洁,还能在不修改原有函数代码的前提下,为函数或类添加新的功能。无论是日志记录、性能监控、权限验证还是缓存机制,装饰器都能派上用场。


一、什么是装饰器

装饰器本质上是一个函数 ,它的作用是接收一个函数或类作为输入,并返回一个被增强后的新函数或类

换句话说:

装饰器 = 高阶函数 + 闭包 的应用。

最简单的形式如下:

python 复制代码
def decorator(func):
    def wrapper():
        print("函数执行前做一些准备工作...")
        func()
        print("函数执行后做一些收尾工作...")
    return wrapper

@decorator
def hello():
    print("Hello, Python!")

hello()

输出结果:

erlang 复制代码
函数执行前做一些准备工作...
Hello, Python!
函数执行后做一些收尾工作...

当我们在 hello() 前加上 @decorator,相当于执行:

python 复制代码
hello = decorator(hello)

这就是装饰器的核心原理。


二、装饰器的执行流程

我们用上面的例子来拆解执行过程:

  1. Python 解释器加载 hello() 时,检测到 @decorator
  2. 执行 decorator(hello),并返回内部函数 wrapper
  3. hello 被替换成 wrapper
  4. 调用 hello() 实际上执行的是 wrapper()

通过这种方式,我们可以在函数执行的前后插入任意逻辑,而不必修改原函数体。


三、带参数的函数装饰器

如果被装饰的函数有参数怎么办? 没问题,只需让 wrapper 支持传入参数即可。

python 复制代码
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(3, 5))

输出:

csharp 复制代码
开始执行函数:add
函数 add 执行结束
8

四、带参数的装饰器(多层装饰)

有时候我们希望给装饰器本身传递参数,比如设置日志级别、权限名称等。

这就需要再包一层函数

python 复制代码
def log(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{level}] 开始执行 {func.__name__}")
            result = func(*args, **kwargs)
            print(f"[{level}] 执行结束 {func.__name__}")
            return result
        return wrapper
    return decorator

@log("INFO")
def multiply(a, b):
    return a * b

multiply(2, 4)

输出:

csharp 复制代码
[INFO] 开始执行 multiply
[INFO] 执行结束 multiply

这里 @log("INFO") 实际上是执行了 log("INFO"),返回一个真正的装饰器函数。


五、同时使用多个装饰器

多个装饰器可以层层嵌套 ,执行顺序为自下而上

python 复制代码
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 hello():
    print("Hello!")

hello()

执行结果:

复制代码
进入 deco1
进入 deco2
Hello!
离开 deco2
离开 deco1

解释:hello = deco1(deco2(hello))


六、functools.wraps 的使用

一个常见问题是:装饰后的函数 __name____doc__ 会被替换为 wrapper 的信息。

为了解决这个问题,Python 提供了 functools.wraps

python 复制代码
from functools import wraps

def logger(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"执行 {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logger
def greet():
    """打印问候语"""
    print("Hi there!")

print(greet.__name__)  # greet
print(greet.__doc__)   # 打印问候语

@wraps(func) 可以保留原函数的元信息,提升代码的可读性和可维护性。


七、类装饰器(进阶)

装饰器不仅可以是函数,也可以是 。 只要类实现了 __call__() 方法,它就能像函数一样被调用。

python 复制代码
class Timer:
    def __init__(self, func):
        self.func = func

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

@Timer
def slow_task():
    import time
    time.sleep(1)
    print("任务完成")

slow_task()

输出:

复制代码
任务完成
slow_task 执行耗时:1.0001 秒

这种写法适合逻辑较复杂、需要保存状态的装饰场景。


八、总结

装饰器是 Python 的一项核心特性,能让代码结构更清晰、功能更模块化。 它的常见应用包括:

  • 日志记录(logger)
  • 性能监控(计时器)
  • 权限验证(auth)
  • 缓存机制(memoization)
  • 接口规范化(API 装饰)

掌握装饰器后,你可以更优雅地编写出功能丰富且可扩展的 Python 程序。


相关推荐
love530love3 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
遇事不決洛必達3 小时前
【Python基础】GIL 锁是什么及其对爬虫的影响
爬虫·python·线程·进程·gil锁
星辰徐哥3 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥3 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约3 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee3 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐3 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs3 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐3 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司3 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录