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 程序。


相关推荐
JELEE.5 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
孫治AllenSun6 小时前
【算法】图相关算法和递归
windows·python·算法
QX_hao7 小时前
【Go】--反射(reflect)的使用
开发语言·后端·golang
小坏讲微服务7 小时前
Docker-compose 搭建Maven私服部署
java·spring boot·后端·docker·微服务·容器·maven
yuuki2332338 小时前
【数据结构】用顺序表实现通讯录
c语言·数据结构·后端
你的人类朋友8 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
史不了9 小时前
静态交叉编译rust程序
开发语言·后端·rust
读研的武9 小时前
DashGo零基础入门 纯Python的管理系统搭建
开发语言·python