坚持原创输出,点击蓝字关注我吧

做者:清菡
博客:oschina、云+社区、知乎等各大平台都有。python
❝因为微信公众号推送改成了信息流的形式,防止走丢,请给加个星标 ⭐,你就能够第一时间接收到本公众号的推送!web
❞
目录
-
1、什么是装饰器 -
1.开放封闭原则(面向对象原则的核心) -
2.装饰器的做用 -
2、实现一个装饰器 -
1.不带参数的装饰器 -
2.装饰器的原理 -
3.组装方便,拆卸也方便 -
4.带参数的装饰器 -
3、通用装饰器 -
4、装饰器装饰类 -
1.不带参数的 -
2.带参数的 -
5、装饰器的应用场景 -
6、补充 -
1.*号的做用 -
2.装饰器装饰类和装饰函数的不一样点
1、什么是装饰器
1.开放封闭原则(面向对象原则的核心)
「对已经实现的功能(项目已经上线了),在这个基础上增长新功能,也能够在它的基础上进行拓展,这个就是开放。若是你要去再修改它内部的代码,这个时候是不容许的,对内部的修改是封闭的。」微信
就是你实现的功能能够拓展,可是你不要去修改它内部的代码。闭包
好比index()
是接口,返回是“这个是网站的首页”,只要调用这个接口就会返回一个“这个是网站的首页。”编辑器
忽然有个需求,在进入网站以前须要先登陆校验一下。这个时候须要拓展,如何拓展?就须要用装饰器了。
函数
def index():
print("这个是网站的首页")
这个已经实现的接口,不能去修改的。测试
2.装饰器的做用
「装饰器可在不更改这个函数里面任何代码的基础上,给它添加新的功能。」flex
2、实现一个装饰器
1.不带参数的装饰器
装饰器其实就是一种闭包的应用。要使用装饰器,能够先定义个闭包函数。把登陆校验的功能写在了闭包函数的内部。网站
把闭包函数当成装饰器来用的话,外面接收的参数须要传一个函数,你要装饰哪一个函数,你就传哪一个函数。url

# 开放封闭原则
def login(func):
def fun():
# 简单的校验
username = 'python01'
password = 'qinghan'
user = input("请输入帐号:")
pw = input("请输入密码:")
# 判断下帐号密码对不对
if username == user and pw == password:
func() # 登陆得帐号密码都正确的状况下,调用这个函数
else:
print("帐号或密码错误")
return fun
@login # 艾特一下这个装饰器
def index():
print("这个是网站的首页")
index()

2.装饰器的原理
「将被装饰的函数看成一个参数传到装饰器中,而且让被装饰的函数名指向装饰器内部的函数,在装饰器的内部函数中用接收到的参数再调用被装饰的函数。」
@login
是 Python 中的一个语法糖。它的做用是:index=login(index)
。传入index
,而后被index
接收。

如何作到经过func()调用原函数?

@login
等于index=login(index)
。
自动将index
看成参数传入login
这个函数里面,去执行login(func)
这个函数,检测到这个fun()
函数,将这段代码:
def fun():
# 简单的校验
username = 'python01'
password = 'qinghan'
user = input("请输入帐号:")
pw = input("请输入密码:")
# 判断下帐号密码对不对
if username == user and pw == password:
func() # 登陆得帐号密码都正确的状况下,调用这个函数
else:
print("帐号或密码错误")
直接跳过。
return fun
直接将结果返回出来。结果返回出来又给index()
接收,调用index()
的时候其实是调用fun()
函数。
执行fun()
函数里面的代码。经过func()
调用原函数,怎么作到的?
fun()
函数是放在index.__closure__
这个属性里面。
而后在下面调用func()
的时候,就是去index.__closure__
这个属性里面找到对应存储的那块代码。
存储的代码就是这个:
def index():
print("这个是网站的首页")
以上,就是装饰器装饰的流程。
3.组装方便,拆卸也方便
我想改为不用登陆也能够访问,直接去掉@login
这个装饰器就能够了。
# 开放封闭原则
def login(func):
def fun():
# 简单的校验
username = 'python01'
password = 'qinghan'
user = input("请输入帐号:")
pw = input("请输入密码:")
# 判断下帐号密码对不对
if username == user and pw == password:
func() # 登陆得帐号密码都正确的状况下,调用这个函数
else:
print("帐号或密码错误")
return fun
# @login # 艾特一下这个装饰器
def index():
print("这个是网站的首页")
# index.__closure__
index()
这样操做,不会对原来有什么影响。
4.带参数的装饰器
实现两个数相加后,又有新的需求,须要能够相乘、相除。
def add(func):
def fun(a, b):
print("相乘", a * b)
print("相除", a / b)
func(a, b)
return fun
@add
def add_num(a, b):
# 打印两个数相加
print("相加:", a + b)
add_num(11, 22)

3、通用装饰器
若是同一个装饰器既要装饰有参数的函数,又要装饰无参数的函数。
那么咱们在传参的时候就设置成不定长参数,这样无论被装饰的函数有没有参数都能用。
# 通用装饰器
def add(func):
def fun(*args, **kwargs):
print("装饰器的功能代码:登陆")
func(*args,**kwargs)
return fun
@add
def index():
print("这个是网站的首页")
@add
def good_list(num):
print("这个是商品列表第{}页".format(num))
index()
print("------------")
good_list(9)
4、装饰器装饰类
1.不带参数的
#装饰器装饰类
def add(func):
def fun(*args, **kwargs):
print("装饰器的功能代码:登陆")
return func(*args,**kwargs)
return fun
@add # MyClass=add(MyClass)
class MyClass:
def __init__(self):
pass
m = MyClass()
print("m的值:",m)

把类看成一个参数传到装饰器里面。return fun
返回的是fun
,MyClass
接收到的是fun
。
MyClass()
调用的是fun
。
执行代码:
def fun(*args, **kwargs):
print("装饰器的功能代码:登陆")
return func(*args,**kwargs)
这里面的功能。
先执行装饰器的功能,return func(*args,**kwargs)
,func()
来自def add(func)
。
调用MyClass
这个类,return func(*args,**kwargs)
建立了个对象,MyClass()
调用完了接收,m 就能接收这个对象了。
这个就是装饰器装饰类的一个原理。
2.带参数的
#装饰器装饰类
def add(func):
def fun(*args, **kwargs):
print("装饰器的功能代码:登陆")
return func(*args,**kwargs)
return fun
@add # MyClass=add(MyClass)
class MyClass:
def __init__(self,name,age):
self.name=name
self.age=age
m = MyClass("qinghan","18")
print("m的值:",m)
这里用的是不定行参数,因此无论你装饰的类是有参数的仍是没参数的,均可以。
5、装饰器的应用场景
1.登陆校验。(在装饰器里面判断下你有没有登陆)
2.函数运行时间统计。
3.执行函数以前作准备工做。
4.执行函数后清理功能。

6、补充
1.*号的做用
*
是进行拆包做用的。把每一个元素拿出来,看成参数进行传递。


一个*
是对元组形式的位置参数进行拆包,两个**
对关键字参数进行拆包。
2.装饰器装饰类和装饰函数的不一样点

类须要把对象返回出来。
公众号「清菡软件测试」首发,更多原创文章:清菡软件测试 116+原创文章,欢迎关注、交流,禁止第三方擅自转载。

感谢关注清菡,欢迎点击在看和转发!
本文分享自微信公众号 - 清菡软件测试(qinghanTester)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。