在讲装饰器之前,要引入一个面向对象的核心原则——“开发封闭原则”。
开放封闭原则主要体现在两个方面:
- 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
- 对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
对于python中的已经完成的函数。我们应该不要对已有函数本身直接进行修改,但是我们仍然在需要新的功能时对其进行扩展。
装饰器的格式
在需要被装饰的函数上一行添加:@decorator_name
一个简单的装饰器可以看到 函数 msg,只是简单输出了一句“hello world”。但是给它加上装饰器之后,再调用函数msg时,它从一个普普通通的“hello world”,变成了华丽(浮夸)的新函数。
def msg_plus(func): def wrapper(): print('一位机智的少年走过来,对你说了一句:') func() print('然后,蹦蹦跳跳地走开了。') return wrapper # 使用装饰器,对这个朴实无华的hello world进行装饰 @msg_plus def msg(): print("hello world") msg() ---------- 输出: 一位机智的少年走过来,对你说了一句: hello world 然后,蹦蹦跳跳地走开了。
这里的msg调用装饰器msg_plus。其本质就相当于:msg = msg_plus(msg)
带参数的装饰器传一个参数时
前面提到了,装饰器实际就是msg = msg_plus(msg),msg函数作为参数传给了msg_plus;返回值是wrapper。
则实际:表面上调用的msg(xx) ,背地里执行的 wrapper(xx)。
所以说,下面代码实际上msg定义的s1 和 wrapper定义的s2是一样的(s1 = s2,之所以这里写不一样是便于区分)。
def msg_plus(func): def wrapper(s2): print('一位机智的少年走过来,对你说了一句:') func(s2) print('然后,蹦蹦跳跳地走开了。') return wrapper # 使用装饰器,对这个朴实无华的hello world进行装饰 @msg_plus def msg(s1): print("说:{}".format(s1)) msg("其实我什么也不想说") ----------- 输出: 一位机智的少年走过来,对你说了一句: 说:其实我什么也不想说 然后,蹦蹦跳跳地走开了。
但我们大多数时候装饰器是给很多函数复用的,每个函数传的参数数量不一定相等。所以我们需要装饰器能接受可变长参数。所以装饰器中的wrapper函数的参数通常定义为*args,**kwargs(接收可变长的参数和可变长关键字参数)。如下:(两段代码实现的是一样的事,只是下面这个可接收可变长参数和可变长关键字参数)
def msg_plus(func): def wrapper(*args, **kwargs): print('一位机智的少年走过来,对你说了一句:') func(*args, **kwargs) print('然后,蹦蹦跳跳地走开了。') return wrapper # 使用装饰器,对这个朴实无华的hello world进行装饰 @msg_plus def msg(s1): print("说:{}".format(s1)) msg("其实我什么也不想说") ----------- 输出: 一位机智的少年走过来,对你说了一句: 说:其实我什么也不想说 然后,蹦蹦跳跳地走开了。装饰器修饰有返回值的函数
这里装饰器里的返回值,可以跟原函数一样,也可以跟原函数不一样,根据实际需求确定。比如我这边的返回值,原函数中原本是没有返回值的。
def msg_plus(func): def wrapper(*args, **kwargs): print('一位机智的少年走过来,对你说了一句:') func(*args, **kwargs) print('然后,蹦蹦跳跳地走开了。') boy_msg = '叽里咕噜,叽里咕噜' return boy_msg return wrapper # 使用装饰器,对这个朴实无华的hello world进行装饰 @msg_plus def msg(s1): print("说:{}".format(s1)) result = msg("其实我什么也不想说") print("他刚说什么?:", result) ----------- 输出: 一位机智的少年走过来,对你说了一句: 说:其实我什么也不想说 然后,蹦蹦跳跳地走开了。 他刚嘎说什么?: 叽里咕噜,叽里咕噜带参数的装饰器
装饰器带参数,将开启套娃模式。以后用多了再补充吧~
装饰器使用场景- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)