装饰器(函数)
装饰器作为一个函数,可以为其他函数在不修改原函数代码的前提下添加新的功能
装饰器的返回值是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等。
装饰器,可以让我们抽离出大量与函数功能本身无关的相同代码并在装饰器函数中使用
装饰器的三个重要要素:
一、作用域
二、高阶函数
三、闭包
一、作用域
在上一节的函数中,我们详细介绍了函数的4种作用域:
L.local,局部作用域;E.enclosing,嵌套作用域;G.global,全局作用域;B.built-in,内建作用域
作用域的优先搜索顺序:局部作用域>>外层嵌套作用域>>当前模块(嵌套函数中)的全局作用域>>python内置作用域;
二、高阶函数
把函数作为参数传入,即函数本身也可以作为一个变量,这样的函数称为高阶函数
高阶函数,就是为了让函数的参数能够接收到别的函数
三、闭包
闭包函数可以脱离函数,在函数的外部单独地进行调用
闭包 = 内部函数 + 定义函数时的环境
闭包的两个条件:1、拥有内部函数;2、对外部环境的一个变量进行引用
- def outer():
- x = 'Hello World!' #定义函数的变量(环境)
-
- def inner(): #条件1,,inner是内部函数
- print(x) #条件2,对外部环境的一个变量进行引用
-
- return inner #结论,内部函数inner就是一个闭包
-
- f = outer()
- f()
- >>> Hello World!
装饰器
Eg1.计算总用时的装饰器
- import time
-
- def show_time(f):
- def inner():
- start = time.time()
- f()
- end = time.time()
- res = end - start
- print('总用时:',res)
- return inner
-
- @show_time #效果相当于 func1=show_time(func1)
- def func1():
- print('-----------功能1-----------')
- time.sleep(2) # 延时2s
-
- @show_time #效果相当于 func2=show_time(func2)
- def func2():
- print('-----------功能2-----------')
- time.sleep(3) # 延时3s
-
- func1()
- func2()
- >>>-----------功能1-----------
- 总用时: 2.0070815086364746
- -----------功能2-----------
- 总用时: 3.0007598400115967
Eg2.带参数的装饰器(如果被装饰的函数中有参数,则装饰器函数中也要带上参数)
- import time
- def show_time(f):
- def inner(*args,**kwargs):
- start = time.time()
- f(*args,**kwargs)
- end = time.time()
- res = end - start
- print('总用时:',res)
- return inner
-
- @show_time #效果相当于 func1=show_time(func1)
- def func3(*args,**kwargs):
- sums = 0
- for i in args:
- sums += i
- print('-----------加法器-----------')
- print('结果是:',sums)
-
- func3(5,6,1,4)
- >>>-----------加法器-----------
- 结果是: 16
- 总用时: 0.0
Eg3.带参数的装饰器(参数为设置的条件,判断是否需要执行修饰器)
- import time
- def flag(flag = 'False'):
- def show_time(f):
- def inner(*args,**kwargs):
- if flag == 'True':
- start = time.time()
- f(*args,**kwargs)
- end = time.time()
- print('time: %s'%(end-start))
- else:
- f(*args, **kwargs)
- return inner
- return show_time
-
- @flag('True') # flag = 'True',运行总用时装饰器
- def add(*args,**kwargs):
- sum = 0
- for i in args:
- sum+=i
- print('-----add的运行结果-----')
- print(sum)
- time.sleep(1)
-
- @flag('False') # flag = 'False',不运行总用时装饰器
- def add1(*args,**kwargs):
- sum = 0
- for i in args:
- sum+=i
- print('-----add1的运行结果-----')
- print(sum)
- time.sleep(1)
-
- add(1,4)
- add1(1,4)
- >>> -----add的运行结果-----
- 5
- time: 1.0008649826049805
- -----add1的运行结果-----
- 5
注意:
- 我们在调用装饰器时,提供了其它参数,@flag()默认的参数为False,则不会输出总用时装饰器;
- 当@flag()参数为True时,输出总用时。这样是在原有的装饰器上加了一层判断;
- 当我们使用@flag(‘True’)调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中;