JakobHu 2020-02-10
############### 装饰器的初成和开放封闭原则 ##############
# 装饰器 # 装饰器非常重要,面试Python的公司必问, # 原则:开放封闭原则 # # 需求:计算程序执行的时间, import time def func(): start = time.time() time.sleep(0.01) print(123) end = time.time() print(end-start) func() # 这种写法如果有100个函数,你都要加一遍这是不行的,太麻烦了, # 第二版 def func(): time.sleep(0.01) print(123) def timer(f): start = time.time() f() end = time.time() print(end-start) timer(func) # 专门写了一个函数用来计算函数的执行时间, # 闭包的写法 def func(): time.sleep(0.01) print(123) def timer(f): def inner(): start = time.time() f() end = time.time() print(end-start) return inner # 这就是一个闭包,因为是函数的嵌套,并且函数内部调用函数外部的参数, # 不修改函数的调用方式,还想要在函数的前后添加功能, # timer就是一个装饰器,对函数有装饰作用, func = timer(func) # inner func() # inner() # 开放封闭原则,适用于对已经固定的额功能,和源码,这个原则是为了程序的稳定性, # 开放就是对已经有的功能的拓展是开放的, # 封闭就是对已经有的功能是不改动的, # 所以使用装饰器是一个非常不错的方式在不改变程序内部的情况下,在程序的前后添加功能,
############### 最终的装饰器版本 ##############
# 最终的装饰器版本 # 解决两个问题, # 1是被装饰函数有返回值 # 2是被装饰函数有参数 import time def timer(f): def inner(*args,**kwargs): # 这个参数就是为了能接收被装饰器函数的参数, start = time.time() ret = f(*args,**kwargs) end = time.time() print(end-start) return ret # 这个地方要返回是因为被装饰函数可能会有返回值, return inner @timer def func(a): time.sleep(0.01) print(123) print(a) return 123 # func = timer(func) # inner ret = func(1) # inner(),这个地方已经是调用的inner了,所以一定要在inner中把被装饰函数的返回值返回回来, print(ret) # def outer(): # def inner(): # return 123 # inner() # # outer() # 这个调用是不会有返回值的,因为你只调用了没有返回值, # 所有有一个装饰器的固定模式 from functools import wraps def outer(func): # 或者叫做wrapper,这就是装饰器的意思,一般会起一个和业务相关的名字, @wraps(func) # 加上这一句,再去打印函数的name的时候,就不会是inner了, def inner(*args,**kwargs): # 一般就是一个inner # 在被装饰函数之前写的东西 ret = func(*args,**kwargs) # 在被装饰函数之后写的东西 return ret return inner @outer # 这一句就是test=outer(test) def test(): """ 函数测试, :return: """ print(123) test() # 这个地方就是inner()了, print(test.__name__) # 这个被装饰器装饰了之后会有问题,inner返回的是inner,而不是test print(test.__doc__)
############### 装饰器进阶--带参数的装饰器 ##############
""" 装饰器进阶 1,带参数的装饰器 场景:就是我写了一个计算代码执行时间的装饰器,然后给每一个函数加上了装饰器, 如果我想要去掉装饰器的时候,就需要一个一个的去掉了,我想要用的时候还需要再一个一个的加上,很麻烦,有什么好的办法? 解决方法:就是给装饰器加上一个参数,然后通过控制参数来判断是否开启装饰器, 参数就叫做flag, 这种代码实现就是使用三层装饰器,这样只需要控制flag就可以控制装饰器是否开启了, """ import time flag = False def timmer_out(flag): def timmer(func): def inner(*args,**kwargs): if flag: start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret else: ret = func(*args, **kwargs) return ret return inner return timmer @timmer_out(flag) def test1(): time.sleep(1) print(123) @timmer_out(flag) def test2(): time.sleep(1) print(123) # @timmer:这一句还好理解就是func=timmer(func) # @timmer_out(flag):为了传递参数,我们可以再次在装饰器外部加一层,用来传递参数, # 这一句要分开看了,第一步是timmer_out(flag),然后返回了timmer,第二步才是@timmer,执行装饰器, test1() test2()
############### 装饰器进阶---多个装饰器装饰一个函数 ##############
""" 装饰器进阶: 2,多个装饰器装饰一个函数, """ def wrapper1(func): def inner(): print(‘wrapper1 ,before func‘) func() print(‘wrapper1 ,after func‘) return inner def wrapper2(func): def inner(): print(‘wrapper2 ,before func‘) func() print(‘wrapper2 ,after func‘) return inner @wrapper2 @wrapper1 def f(): print(‘in f‘) f() """ 执行结果: wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func 说明了几个问题: 1,多个装饰器是把函数之前的装饰代码都执行之后,然后才是执行被装饰函数,最后是函数之后的装饰代码 2,函数之前的执行顺序是谁在上面执行谁,这是从上到下,函数之后的执行顺序是谁在下面执行谁,这是从下往上, 就像是俄罗斯套娃,进的时候从外往里,出的时候从里往外, """