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,日常开发中最常见的装饰器用法就够用了。下次看到 @ 开头的写法,别再觉得神秘——它只是给函数穿上的一件“外衣”。
- 点赞
- 收藏
- 关注作者
评论(0)