函数进阶之闭包、装饰器
一、函数名
函数名本质上就是函数的内存地址
1.函数名可以被引用
def func(): print('in func') f = func print(f)
2、函数名可以赋值给其他变量
3、可以被当作容器类型的元素
def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1,f2,f3] d = {'f1':f1,'f2':f2,'f3':f3} #调用 l[0]() d['f2']() 可以当做容器类型的元素
4、函数名可以当做函数的参数
5、函数名可以当做函数的返回值
def f1(): print('f1') def func1(argv): argv() return argv f = func1(f1) f() 可以当做函数的参数和返回值
函数是第一类对象
第一类对象(first-class object)指
1、可在运行期创建
2、可用作函数参数或返回值
3、可存入变量的实体。
二、闭包
闭包是内层函数对外层函数*(非全局)变量的引用,该内层函数为闭包函数。
函数内部定义的函数称为内部函数
如何实现对内层函数的调用?
def func(): name = 'eva' def inner(): print(name) return inner f = func() f()
判断闭包函数的方法__closure__-----print(inner.__closure__)
#输出的__closure__有cell元素 :是闭包函数 def func(): name = 'eva' def inner(): print(name) print(inner.__closure__) return inner f = func() f() #输出的__closure__为None :不是闭包函数 name = 'egon' def func2(): def inner(): print(name) print(inner.__closure__) return inner f2 = func2() f2()
闭包的嵌套
def wrapper(): money = 1000 def func(): name = 'eva' def inner(): print(name,money) return inner return func f = wrapper() i = f() i() 闭包嵌套
闭包的好处:保护内存,闭包函数在内存中的局部命名空间不会随着函数的结束而结束
三、装饰器
1、装饰器本质上是闭包函数
在不改变被装饰的函数及被装饰的函数的执行方式下,
给函数增加额外的功能.日志,测试执行时间等
2、装饰器形成过程
import time def func1(): print('in func1') def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner func1 = timer(func1) func1() 装饰器---简单版
def timer(func): def inner(a): start = time.time() func(a) print(time.time() - start) return inner @timer def func1(a): print(a) func1(1) 装饰器——带参数的装饰器
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) def func1(): print('in func1') func1() 装饰器---语法糖
import time def timer(func): def inner(*args,**kwargs): start = time.time() re = func(*args,**kwargs) print(time.time() - start) return re return inner @timer #==> func1 = timer(func1) def func1(a,b): print('in func1') @timer #==> func2 = timer(func2) def func2(a): print('in func2 and get a:%s'%(a)) return 'fun2 over' func1('aaaaaa','bbbbbb') print(func2('aaaaaa')) 装饰器---通用装饰器
def wrapper(func): def inner(*args,**kwargs): '''执行函数前操作''' ret = func(*args,**kwargs) '''执行函数后的操作''' return ret return inner
三、开放封闭 原则
1.对扩展是开放的
为什么要对扩展开放呢?
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。
四,装饰器的主要功能和固定结构
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper 装饰器的固定格式--wraps版
五、带参数的装饰器
假如你有成千上万个函数使用了一个装饰器,现在你想把这些装饰器都取消掉,你要怎么做?
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func() 带参数的装饰器
f__doc__ # 获取函数的说明信息
f__name__ #获取函数的名字
六、多个装饰器装饰一个函数
def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func() 多个装饰器装饰同一个函数 有些时候,我们也会用到多个装饰器装饰同一个函数的情况。 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() 多个装饰器装饰一个函数
注:*args # *接受函数时,*是聚合
传递参数时,*是打散