一、什么是闭包函数?
在听了Egon老师的讲解后我有了一些见解来跟xdm分享:
闭包函数=名字空间与作用域+函数嵌套+函数对象 ‘闭'函数指的该函数是内嵌函数 ‘包’函数指的该函数包含对外层函数作用域名字的引用(不是对全局作用域)
注意:内部函数包含对外部作用域而非全局作用域的引用
来为大家举个例子:
x=100 def f1(): x=1 def f2(): print(x) return f2 # 可以理解为f2就是被f1包起来的函数,它的内容(如x)是外层函数f1(x=1)所提供而非全局的作用域(x-100)所提供 f=f1()# ==》f=f1的return=》f=f2==》得到的是f2的内存地址 print(f)# ==><function f1.<locals>.f2 at 0x0000022DA470D3A0> f()#==》f2()==>1
二、无参装饰器
首先大家要明白装饰器就是闭包函数的一种应用场景
那xdm知道-为何要用装饰器吗?
根据开放封闭原则:对修改封闭,对扩展开放
有时大家在做项目时,你写好了一个功能,当你想要为这个功能添加或修改一些功能时,如果不用装饰器,你可能要在原来的功能代码上进行修改,要是每次都要在原来的代码上进行修改,大家会不会觉得太累了呢?特别是你要在别人写的功能代码上进行修改时。而装饰器遵循的开放封闭原则很好的避免了这个问题。
什么是装饰器?
装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
强调装饰器的原则:
1 不修改被装饰对象的源代码
2 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
首先我来跟大家列下无参装饰器的模板:
# 无参装饰器模板 '''def 无参装饰器(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper @无参装饰器 def 被装饰函数(): ... '''
下面我们来用无参装饰器的模板来进行一个小的案例:
import time def timmer(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print(stop - start) return res return wrapper # 上面者段代码的功能就是计算传进来的函数func运行所需的时间 # 当运行到@装饰器时,不会去运行装饰器下面的函数,调用的是装饰器的函数功能 @timmer#==>index=tmmer(index) def index(x,y): time.sleep(2) print('index %s %s'%(x,y)) return x+y index(2,3) # 输出结果为: # index 2 3 # 2.006439685821533
这就是套用的无参装饰器的模板,但大家想必也很疑惑和好奇,它的原理是什么,下面我将不用装饰器,来实现上面一样的功能和输出结果
def index(x,y): time.sleep(2) print('index %s %s'%(x,y)) return x+y def outter(func): def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print(stop-start) return res return wrapper index=outter(index) # 将index函数作为参数传入outter(func) # ==》将outter的返回值传给变量index(注意区分,第一个index和第二个index) # ==》index=wrapper==》index指向的是wrapper的内存地址而非index函数的内存地址 index(2,3)# ==》其实运行的是wrapper(2,3) # start=time.time() 记录运行func()开始前的时间 # res=func(*args,**kwargs)==>res=index(2,3)==>index是传进来的参数,(2,3)是wrapper(2,3)的参数 # stop=time.time() 记录func()结束后的时间 # print(stop-start)打印时间差即函数运行的时间 # return res 返回调用index()return的结果 ,若没有return 则默认为None print('====>',index(2,5))
想必大家应该也明白了其中的原理,有参的装饰器运行的原理也和上面的无参装饰器的原理差不多。当有多个装饰器装饰一个函数时,从最下面的装饰器开始调用
def outter1(func1): #func1=wrapper2的内存地址 print('加载了outter1') def wrapper1(*args,**kwargs): print('执行了wrapper1') res1=func1(*args,**kwargs) return res1 return wrapper1 def outter2(func2): #func2=wrapper3的内存地址 print('加载了outter2') def wrapper2(*args,**kwargs): print('执行了wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2 def outter3(func3): # func3=最原始的那个index的内存地址 print('加载了outter3') def wrapper3(*args,**kwargs): print('执行了wrapper3') res3=func3(*args,**kwargs) return res3 return wrapper3 @outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址 @outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址 @outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址 def index(): print('from index') print('======================================================') index() # 输出结过如下: ’‘’ 加载了outter3 加载了outter2 加载了outter1 ====================================================== 执行了wrapper1 执行了wrapper2 执行了wrapper3 from index ‘’‘
三、有参装饰器
有参装饰器模板 '''def 有参装饰器(参数): def outter(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper return outter @有参装饰器(参数) def 被装饰函数(): ... '''
原理无非和无参装饰器一样,就不为大家详细介绍啦,有兴趣的兄弟可以课下自己套用模板试一下,不会的可以私信我欧,希望大家喜欢,一起进步!要是喜欢的话欢迎大家来关注我欧~有不足的地方欢迎大家指出,会继续为xdm更新的