装饰器
开放封闭原则:
什么是开放封闭原则?有的同学问开放,封闭这是两个反义词这还能组成一个原则么?这不前后矛盾么?其实不矛盾。开放封闭原则是分情况讨论的。
我们的软件一旦上线之后(比如你的软件主要是多个函数组成的),那么这个软件对功能的扩展应该是开放的,比如你的游戏一直在迭代更新,推出新的玩法,新功能。但是对于源代码的修改是封闭的。你就拿函数举例,如果你的游戏源代码中有一个函数是闪躲的功能,那么你这个函数肯定是被多个地方调用的,比如对方扔手雷,对方开枪,对方用刀,你都会调用你的闪躲功能,那么如果你的闪躲功能源码进行改变了,或者调用方式改变了,当对方发起相应的动作,你在调用你的闪躲功能,就会发生问题。所以,开放封闭原则具体定义是这样:
1.对扩展是开放的(增加新功能)
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的(修改已经实现的功能)
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对函数内部进行修改,或者修改了函数的调用方式,很有可能影响其他已经在使用该函数的用户。OK,理解了开封封闭原则之后,我们聊聊装饰器。
什么是装饰器?从字面意思来分析,先说装饰,什么是装饰? 装饰就是添加新的,
比如我现在不会飞,怎么才能让我会飞?给我额外增加一个翅膀,我就能飞了。那么你给我加一个翅膀,它会改变我原来的行为么?我之前的吃喝拉撒睡等生活方式都不会改变。它就是在我原来的基础上,添加了一个新的功能。
今天我们讲的装饰器(翅膀)是以功能为导向的,就是一个函数。
被装饰的对象:我本人,其实也是一个函数。
所以装饰器最终最完美的定义就是:在不改变原被装饰的函数的源代码以及调用方式的基础下,额外增加新的的功能。
装饰器: 用来装饰的工具 ---开放封闭原则
作用:在不修改源函数及调用方式前提下额外增加一些功能
函数嵌套:
闭包
简单版的装饰器
版一:
import time
# print(time.time())#格林尼治时间
start_time =time.time()
def func():
time.sleep(2)#睡眠模拟网络延迟
print("我要飞")
func()
end_time = time.time()
print(end_time-start_time)
版本二
import time
def times(f):
start_time = time.time()
f()
print(time.time() - start_time)
def foo():
time.sleep(3) #睡眠 (模拟网络延时)
print("我是小明,我飞的比你高")
def func():
time.sleep(1) #睡眠 (模拟网络延时)
print("我是业儿,我起不来")
s = func
func = times
s = foo
foo = times
foo(s)
版本三(装饰器初始)
import time
def times(f):
def inner():
start_time = time.time()
f()
print(time.time() - start_time)
return inner
def foo():
time.sleep(1) #睡眠 (模拟网络延时)
print("我是李业,我快!")
foo = times(foo)
foo()
版本四(第二版装饰器)
def wrapper(f):
def inner():
f()
return inner # 切记不要加括号
def func():
print("这是func函数,李业还是不行")
func = wrapper(func)
func()
结果
这是func函数,李业还是不行
def wrapper(f):
def inner(*args,**kwargs):
f(*args,**kwargs) # func("alex")
return inner # 切记不要加括号
def func(*args,**kwargs):
print(f"这是{args}和{kwargs}函数,李业还是不行")
func = wrapper(func)
func("alex","sur",a = 1,b=2,c="cqk")
结果
这是('alex', 'sur')和{'a': 1, 'b': 2, 'c': 'cqk'}函数,李业还是不行
# low版
import time
def wrapper(f):
def inner(*args,**kwargs):
"被装饰前"
start_time = time.time()
f(*args,**kwargs) # func("alex")
print(time.time() - start_time)
"被装饰后"
return inner # 切记不要加括号
def func(*args,**kwargs):
print(f"这是{args}函数,李业还是不行")
time.sleep(2) #模拟网络延时
func = wrapper(func)
func("alex","sur")
结果
这是('alex', 'sur')和{'a': 1, 'b': 2, 'c': 'cqk'}函数,李业还是不行
这是('alex', 'sur')函数,李业还是不行
2.000854015350342
语法糖--必须放在函数定义正上方 @装饰器的名
# 高级
import time
def wrapper(f):
def inner(*args,**kwargs):
"被装饰前"
start_time = time.time()
f(*args,**kwargs) # func("alex")
print(time.time() - start_time)
"被装饰后"
return inner # 切记不要加括号
@wrapper # func = wrapper(func)
def func(*args,**kwargs):
print(f"这是{args}函数,李业还是不行")
time.sleep(2) #模拟网络延时
@wrapper # foo = wrapper(foo)
def foo(*args,**kwargs):
print(f"这是{args}函数,常鑫穿齐*小短裤")
time.sleep(3) #模拟网络延时
# func = wrapper(func)
# foo = wrapper(foo)
func("alex","sur")
foo("alex","sur")
结果:
这是('alex', 'sur')函数,李业还是不行
2.001922130584717
这是('alex', 'sur')函数,常鑫穿齐*小短裤
3.000284433364868
import time
def wrapper(f):#f = func
def inner(*args,**kwargs):
"被装饰前"
start_time = time.time()
ret = f(*args,**kwargs) # func("alex")
print(time.time() - start_time)
"被装饰后"
return ret
return inner # 切记不要加括号
@wrapper # func = wrapper(func)
def func(*args,**kwargs):
print(f"这是{args}函数,李业还是不行")
time.sleep(2) #模拟网络延时
return "alex"
print(func())
结果:
这是()函数,李业还是不行
2.000833511352539
alex
标准版装饰器:
def wrapper(f):
def inner(*args,**kwargs):
'''执行被装饰函数之前的操作'''
ret = f(*args,**kwargs)
'''执行被装饰函数之后的操作'''
return ret
return inner
@wrapper
def func(*args,**kwargs):
pass
func("sss",a=1)
-
看代码写结果:
def wrapper(f): def inner(*args,**kwargs): print(111) ret = f(*args,**kwargs) print(222) return ret return inner def func(): print(333) print(444) func() print(555) 444 333 555
-
编写装饰器,在每次执行被装饰函数之前打印一句’每次执行被装饰函数之前都得先经过这里’。
def func(f): def foo(): print('每次执行被装饰函数之前都得先经过这里') f() return foo @func def fun(): print("你好啊") fun()
-
为函数写一个装饰器,把函数的返回值 +100 然后再返回。
@wrapper def func(): return 7 result = func() print(result)
def wrapper(f): def foo(): return f()+100 return foo @wrapper def func(): return 7 result = func() print(result)
-
请实现一个装饰器,通过一次调用使被装饰的函数重复执行5次。
def wrapepr(f): def foo(): for i in range(5): f() return foo @wrapepr def f1(): print("你好啊") f1()
-
请实现一个装饰器,每次调用函数时,将被装饰的函数名以及调用被装饰函数的时间节点写入文件中。
可用代码: import time struct_time = time.localtime() print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time)) # 获取当前时间节点 def func(): print(func.__name__) 函数名通过: 函数名.__name__获取。
import time
def wrapper(f):
def foo():
with open("time","a",encoding="utf-8") as f1:
struct_time = time.localtime()
f1.write(time.strftime("%Y-%m-%d %H:%M:%S\t",struct_time))
f1.write(f.__name__+"\n")
f()
return foo
@wrapper
def func():
print("你好啊")
func()