Python 装饰器入门:给函数穿上一件“外衣”

举报
yd_294192959 发表于 2026/11/08 06:13:11 2026/11/08
【摘要】 学习 Python 到一定阶段,总会遇到一个看起来很神奇的写法:函数上面多了一行以 @ 开头的语句,函数本身没有任何改动,行为却变了。这就是装饰器。今天这篇短文,就把装饰器讲清楚。 一、装饰器是什么简单来说,装饰器就是一个函数:它接收另一个函数作为参数,返回一个新的函数。新的函数在原有功能的基础上,增加了一些额外的行为。打个比方,原函数是一件衣服,装饰器就是给它加了一件外衣,衣服本身没变,但...

学习 Python 到一定阶段,总会遇到一个看起来很神奇的写法:函数上面多了一行以 @ 开头的语句,函数本身没有任何改动,行为却变了。这就是装饰器。今天这篇短文,就把装饰器讲清楚。

一、装饰器是什么

简单来说,装饰器就是一个函数:它接收另一个函数作为参数,返回一个新的函数。新的函数在原有功能的基础上,增加了一些额外的行为。打个比方,原函数是一件衣服,装饰器就是给它加了一件外衣,衣服本身没变,但穿上之后看起来不一样了,也多了一层保暖的效果。

二、写出第一个装饰器

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

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

say_hello()

运行之后,先打印“开始执行”,再打印问候语,最后打印“执行结束”。@my_decorator 这一行,等价于 say_hello = my_decorator(say_hello),只是写法更简洁,意图也更清晰。

三、让装饰器支持参数

上面的 wrapper 没有参数,只能装饰无参函数。如果原函数需要参数,wrapper 也要把参数接收并转发过去:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("开始执行")
        result = func(*args, **kwargs)
        print("执行结束")
        return result
    return wrapper

*args 和 **kwargs 会把所有位置参数和关键字参数原样传给原函数,return 则把结果带回来。这样写出来的装饰器,几乎可以装饰任何函数。

四、别忘了 functools.wraps

装饰之后,函数的 __name__ 会变成 wrapper,调试和写文档时容易造成困扰。标准库提供了 functools.wraps,只需在 wrapper 上再加一行装饰器,就能保留原函数的名称和文档字符串:

import functools

def my_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

这是一个值得养成的好习惯,写装饰器时顺手加上,几乎没有成本。

五、装饰器能用来做什么

装饰器最适合做那些“横切”在很多函数之上的通用逻辑。比如给接口函数统一计时、记录日志、做结果缓存,或者在执行前校验权限。把这些逻辑写进装饰器,业务函数本身保持干净,改动一处即可处处生效。Web 框架里用装饰器注册路由,也是装饰器的典型应用。

六、使用时注意三点

第一,多个装饰器叠加时,离函数最近的先执行,理解执行顺序能少踩很多坑。第二,装饰器在函数定义时就执行,而不是调用时才执行。第三,装饰器也可以带参数,这时需要再包一层工厂函数,先接收参数,再返回真正的装饰器。

小结

装饰器的核心就一句话:不改动原函数代码,为它增加额外功能。先从无参装饰器入手,掌握 *args、**kwargs 的转发,再记住 functools.wraps,日常开发中最常见的装饰器用法就够用了。下次看到 @ 开头的写法,别再觉得神秘——它只是给函数穿上的一件“外衣”。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。