(小甲鱼python)函数笔记合集五 函数(V)总结 函数的闭包(工厂函数)

一、基础复习

  1. 函数的基本用法 创建和调用函数 函数的形参与实参等等
  2. 函数的几种参数 位置参数、关键字参数、默认参数等
  3. 函数的收集参数*args **args 解包参数详解
  4. 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解

二、函数的闭包(工厂函数)

1.不通过外层函数funA()访问内层函数funB()
函数进行嵌套,只能通过外层函数funA()访问内层函数funB()。
闭包也称为工厂函数。
例1和例2通过外层函数funA调用funB()

#例1:
>>> def myfunc():
	x=520
	print(x)
	
>>> myfunc()
520
>>> print(x)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    print(x)
NameError: name 'x' is not defined
>>> 
#例2:
>>> def funA():
	x=880
		def funB():
			print(x)
		funB()

>>> funB()
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    funB()
NameError: name 'funB' is not defined
>>> 
>>> funA()
880
>>> 

不通过funA()函数调用funB(),通过另一种方法访问内层函数funB(),也就是闭包。具体看例3和例4的解释

#例3:
>>> def funA():
	x=880
		def funB():
			print(x)
		return funB    #将funB()作为返回值返回

>>> funA()   #得到funB()函数的一个引用
<function funA.<locals>.funB at 0x00000208BE292488>
>>> funA()()  #通过funA()()访问到内层函数funB()
880
>>> funny=funA()   #调用funA()函数,结果返回给一个变量。
>>> funny()   # 
880

例4:
对于嵌套外层函数的作用域会通过某种形式保存下来,尽管这个函数已经调用完了,但外层作用域里面的变量是会保存下来的。
代码解释:
闭包会把你的参数保存下来,创建一个不完整的函数,也就是只有exp这个参数,后续根据刚刚说的调用了里面的参数也就是给了base参数形成完整的函数。
1.第一个return返回的是计算的结果,第二个return返回的是exp_of函数本身。
2.执行power函数,返回的是exp_of函数的引用,相当于返回了已经定义exp变量的第一个return。
3.那么square()就是一个函数,括号里写的就是base变量。
return的意义在于返回函数的结果。

>>> def power(exp):
		def exp_of(base):
			return base ** exp    # base的exp次方
		return exp_of

>>> square=power(2)   #square指向了exp_of函数,exp的值是2。
>>> cube=power(3)
>>> square(2)   # 2的2次方
4
>>> square(5)  #5的平方
25 
>>> power(2)(5)   # 另一种表达,第一次square=power(2),第二次调用square(5)相当于power(2)(5)
25
>>> 

例5:
代码解释:nonlocal关键字,会把内层函数x,y的结果赋值到x,y,所以每调用一次内层函数,都重新给外层赋值一次

>>> def outer():
	x=0
	y=0
	def inner(x1,y1):
		nonlocal x,y
		x+=x1
		y+=y1
		print(f"现在,x={x},y={y}")
	return inner

>>> move=outer()
>>> move(1,2)
现在,x=1,y=2
>>> move(-2,2)
现在,x=-1,y=4

课后题:
1.为什么将闭包称之为 “工厂函数”?
答:顾名思义,工厂函数就是能产生函数的函数。
解析:

>>> def power(exp):
...     def exp_of(base):
...         return base ** exp
...     return exp_of
... 
>>> square = power(2)
>>> cube = power(3)
>>> square(5)
25
>>> cube(5)
125

上面代码中,power() 函数就是一个工厂函数,根据其参数的不同,得到了两个不同的“生产线”函数,一个是 square(),一个是 cube(),前者是返回参数的平方,后者是返回参数的立方。
2.实现闭包必须要用到嵌套函数吗?
答:是的,必须的。
解析:
在本质上,闭包就是将函数内部和函数外部连接起来的桥梁。
对于嵌套函数来说,外层函数的作用域是会通过某种形式保存下来的,内层函数可以在外层函数调用周期结束后,仍旧能访问到外层函数的变量(及参数)。
3.请问下面代码会打印什么呢?

>>> def funA():
...     x = 520
...     def funB():
...         print(x)
...     return funB
...
>>> funny = funA()
>>> del funA
>>> funny()
>>> # 请问这里会打印什么内容?

答:520。
解析:
del 语句这里会删除 funA() 函数吗?
答案是“会删,但又不会完全被删”!一个对象是否会被删除,取决于它是否还有人记得(引用)它。funA() 函数这里确实是已经被删除了,但它的内部有一个 funB() 函数仍然被 funny 引用着。换言之,当 return funB 语句被执行之后,funA() 函数的“影子”就残留在内存中了。哪怕 funA() 函数被删除了,它的“影子”也会一直在,只有当引用 funB() 函数的 funny 被删除,“影子”才会被随之抹去。
4.请问下面代码执行后,x 变量的值分别是多少?

def outter():
    def innerA():
        x = 100
    
    def innerB():
        nonlocal x
        x = 250
    
    def innerC():
        global x
        x = 520
    
    x = 880
    
    innerA()
    print(f"调用完 innerA() 函数之后,x = {x}")
    
    innerB()
    print(f"调用完 innerB() 函数之后,x = {x}")
    
    innerC()
    print(f"调用完 innerC() 函数之后,x = {x}")
    
outter()
print(f"此时此刻,全局变量 x = {x}")

答:

调用完 innerA() 函数之后,x = 880
调用完 innerB() 函数之后,x = 250
调用完 innerC() 函数之后,x = 250
此时此刻,全局变量 x = 520

解析:
这里需要注意的是LEGB 规则以及 nonlocal 和 global 语法。
这里要注意的关键是 x = 880 是定义在 outter() 函数中的局部变量。但相对于 innerA()、innerB() 和 innerC() 这三个函数来说,它又是处于 LEGB 中的 E(嵌套函数的外层函数作用域),使用 nonlocal x 可以修改它的值。global x 修改的是全局变量的 x(注意:如果不存在,就会创建一个)。
5.如果想要函数 funA() 的调用结果如下,它的函数体应该如何定义?

>>> # 请定义 funA() 函数,使其调用结果如下。
>>> funA(3)(4)(5)
60

答:

>>> def funA(x):
...     def funB(y):
...         def funC(z):
...             return x * y * z
...         return funC
...     return funB
...
>>> funA(3)(4)(5)
60

6.挑战一下自己,请将下面这个闭包函数转换为 lambda 表达式的形式?

>>> def maker(n):
...     def action(x):
...         return x ** n
...     return action
>>> f = maker(2)
>>> f(3)
9
>>> f(5)
25

答:

>>> f = lambda n : lambda x : x ** n
>>> g = f(2)
>>> g(3)
9
>>> g(5)
25

题目来自小甲鱼函数(V)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值