闭包、装饰器、回调函数知识回顾
1. 闭包
在一些解释性语言(JavaScript、python、PHP等)中,
在一个函数中可以嵌套另外另外一个函数的,如果内部函数引用了外部函数的变量,
并且外部函数把内部函数的函数名做为了返回值,这就形成了一个闭包
1.1 函数的执行过程
在像python这样的解释性语言中,函数可以看成是一个特殊的变量,这个变量中保存的是函数的入口地址
比如我定义了一个函数func1,函数func1这个名称可以看成是一个特殊的变量,这个变量中保存的是函数的入口地址
def func1():
pass
我们都学习过面向对象
比如这里有一个列表
a = [1,2,3]
a 保存的是这个列表 [1,2,3]吗?
不是,a保存的是这个列表的首元素的地址
回到函数func1,现在在下方调用一下这个函数,表示要取运行这个函数,运行的方式是通过函数func1这个特殊的变量,找到函数的入口地址,找到函数的入口地址后,就找到这个函数的源码了(当然这个源码是被编译成机器可执行的二进制的格式),然后按照源码进行执行,这就是函数的执行过程
def func1():
pass
func1()
这里举个例子,在JavaScript中,怎么定义函数的: var一个变量f ,后面是函数体,这里尤其更能体现函数是一个特殊的变量
var f = function(){}
1.2 闭包
在外部函数func1里定义一个内部函数func2,内部函数调用了外部函数的变量a,在内部函数中打印一下c=b+a的值,然后在外部函数func1中将内部函数func2的入口地址return出去
现在,这个函数就形成了一个闭包
通过传一个参数90进去,调用一下func1函数,
这个90起什么作用?
这个其实不起作用,只是定义函数的时候有一个参数p,所以用这个func1函数的时候需要有一个参数,数字随便取,反正在函数内部又没有用到
运行一下这个程序,我们执行函数func1,函数func2能执行吗?
def func1(p):
a = 100
def func2(q):
b = 200
print('b=',b)
print('a=',a)
c = b + a
print('c=', c)
return func2
func1(90)
答案是: 肯定不能执行
这是为什么捏?func2是一个变量,这个变量下存的是这一串代码的入口地址,
b = 200
print('b=',b)
print('a=',a)
c = b + a
然而我们并没有去调用这个入口地址,所以这个函数并没有执行,如果执行了,那么必然会打印内容
那么能不能再外部调用一下func2函数呢?
def func1(p):
a = 100
def func2(q):
b = 200
print('b=',b)
print('a=',a)
c = b + a
print('c=', c)
return func2
func1(90)
func2(10)
你会发现,输入这行代码func2(10)就报红了,为什么?
func2是func1的内部函数,相当于一个局部变量,怎么能调呢?
但是能不能获取到func2的信息呢?当然是能啊
在函数func1中,func2被当成是一个返回值=被func1返回出去了
也就是return func2,现在修改一下这串代码
用一个变量f来接受一下func1,打印一下f的形象,不对,是信息,要是理解不了,简单一点,不要f了,直接print(func1(90)),一样的意思
def func1(p):
a = 100
def func2(q):
b = 200
print('b=',b)
print('a=',a)
c = b + a
print('c=', c)
return func2
f = func1(90)
print(f)
查看一下打印的信息
<function func1.<locals>.func2 at 0x000001B5B5B14048>
这是一个定义在func1下的func2这个对象,后面是func2 这个对象的入口地址
既然f身上有func2的入口地址,那么是不是通过f可以调用func2,对的
def func1(p):
a = 100
def func2(q):
b = 200
print('b=',b)
print('a=',a)
c = b + a
print('c=', c)
return func2
# print(func1(90))
f = func1(90)
# print(f)
f(1000)
运行一下这个程序,然后可以发现打印了fun2中的信息
b= 200
a= 100
c= 300
此时就在外部使用了内部函数
1.3 闭包的使用 装饰器
装饰器是一种设计模式:在不改变原有模块的基础上,可以在适当的地方给该功能模块添加一些额外的功能,这写新增的功能仅仅在该装饰器环境下适用,脱离了这个环境新增的功能就会失效
装饰器的作用:降低代码的耦合度,提高模块内部的聚合程度,使得模块的适用性更强,有利于系统的维护以及后期版本迭代开发
装饰器在python中的实现,采用闭包
定义一个外函数outer,outer函数的调用需传入一个参数f(这个参数可以是一个数,也可以是一个函数,等下在下面在定义这个被当作参数传入的函数)
在outer函数里定义一个内函数inner,inner函数将outer函数的参数f当做函数来使用
最后outer函数将inner函数当成返回值返回出去
现在这个outer函数符合闭包的规则,所以它实质是一个闭包
def outer(f):
def inner():
print("+++++++++")
f() #把外部函数的f变量当做函数来使用
print("++++++++")
return inner
接下来在下面定义一个函数
然后调用它,右键运行
def myfunc():
print("Hi girl! Are you free tonight?")
myfunc()
此时myfunc函数只打印
Hi girl! Are you free tonight? 这一句话
关键来了,现在给这个myfunc函数添加装饰器
# 装饰器在python中的实现,采用闭包
def outer(f):
def inner():
print("+++++++++")
f() #把外部函数的f变量当做函数来使用
print("++++++++")
return inner
# 定义一个功能函数
def myfunc():
print("Hi girl! Are you free tonight?")
# myfunc()
func = outer(myfunc)
# func()就是myfunc用outer这个装饰器装饰以后的函数
# 调用这个装饰后的函数
func()
运行一下
打印的结果是
+++++++++
Hi girl! Are you free tonight?
++++++++
是不是有点晕,没事,简单解释一下,这个的实质就是:
将myfunc函数当成参数,传入了outer函数,然后inner函数调用了这个myfunc函数,然后outer函数将inner函数返回出去。
inner函数起了什么作用呢?
就是多打印了两行+++++++++
如果你问我,outer函数的参数不是f吗?inner里的函数不也是f()吗?
嗯~这个解释起来,就会很累了,所以,要是想不明白,不要想太深,你可以简单的认为f就是myfunc函数
f只是代表outer函数传入的参数,而实际上我们传入的是myfunc函数
换一种通俗易懂的说法,就是渣男进行了包装,带了顶帽子,实质上渣男的性质没变,只是加了修饰而已
所以,装饰器也可以是这种帽子的形式
# 装饰器在python中的实现,采用闭包
def outer(f):
def inner():
print("+++++++++")
f() #把外部函数的f变量当做函数来使用
print("++++++++")
return inner
# 定义一个功能函数
def myfunc():
print("Hi girl! Are you free tonight?")
# myfunc()
func = outer(myfunc)
# func就是myfunc用outer这个装饰器装饰以后的函数
# 调用这个装饰后的函数
func()
@outer
def myfunc2():
print('gun!')
myfunc2()
看一下打印的内容
+++++++++
Hi girl! Are you free tonight?
++++++++
+++++++++
gun!
++++++++
现在,认清渣男了吗?
2、回调函数
认清了渣男的帽子,再认清一下备胎手段
首先定义一个主调函数,主调函数需要传入3个参数,啊,a,b,c
这里c比较可怜,是一个函数
当函数A运行的时候,参数c是被调函数B,函数B使用了函数A中的变量a、b,使a、b相乘,得到了结果k
# 回调
# 主调函数
def funcA(a,b,c):
print("我是主调函数")
p = a*b
c(p) # 把变量c当做一个函数来用
# 被调函数
def funcB(k):
print("我是被调函数")
print("被调函数的参数值为K=",k)
# 调用函数funcA
funcA(10,20,funcB) # funcA要求传递三个参数,并且第三个参数必须是函数,而且要求传的这个函数要有1个形参
# 被调函数什么时候调用,需要接收什么样的参数完全取决于主调函数
查看一下打印结果
我是主调函数
我是被调函数
被调函数的参数值为K= 200
这就是所谓的被人骗了还帮别人数钱,是不是像极了爱情