闭包、装饰器、回调函数知识回顾

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

这就是所谓的被人骗了还帮别人数钱,是不是像极了爱情

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值