Python学习第三十九天—函数5(闭包)

[复制链接]
15271953841 发表于 2024-3-3 15:10:42 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

×
本帖最后由 15271953841 于 2024-3-4 20:12 编辑

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
一、先回顾复习上一节的内容
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
def funA():
    x=880
    def funB():
        print(x)
    funB()

   
funB()
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    funB()
NameError: name 'funB' is not defined. Did you mean: 'funA'?
funA()
880
有没有办法,不通过funcA函数来调用funB呢?
二、闭包(closure)
def funA():      
    x=880
    def funB():
        print(x)
return funB    (将函数作为返回值,只写它的名字就可以了,不用加上小括号,函数只在定义和调用时才会用到小括号)  
(先调用了funA函数,然后我们将它的结果给了funny变量,这时funA函数已是气数已尽的了,已经是结束的了,理论上它所拥有的变量也消失殆尽,但是我们却通过funny变量给访问到了,有那种“通灵”的感觉,明明在理论上已经不存在了,但却能通过间接的方式给访问到,那么LEGB的E就是拥有这么一个神奇的特性,对于嵌套函数来说,外层函数的作用域是会通过某种形式给保存下来的,尽管这个函数已经调用完了,但是外层作用域里的变量它是会保存下来的,它并不会像局部作用域那样,调用完就消失了。

funA
<function funA at 0x00000265AB2FDD00>   (得到的是funB函数的引用)
funA()()    (把funA()当作一个函数,再在后面加上小括号调用,两个小括号,相当于调用了funB,返回可以给这个返回值赋给其他变量,而调用就直接输出,不能赋给其他变量)
880
funny=funA()
funny()
880
什么是闭包,所谓闭包,有人称之为工厂函数,工厂是指来料加工,批量生产。
def power(exp):      (定义 外部函数(参数))
    def exp_of(base):    (定义 内部函数(参数))
        return base ** exp     (** 表示幂运算)
    return exp_of

square=power(2)
cube=power(3)
square(2)
4
square(5)
25
cube(2)
8
cube(5)
125
power(2)(2)
4
power(2)(5)
25
power(3)(2)
8
power(3)(5)
125
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
内层函数能够记住外层函数的作用域这个特性,并且使用nonlocal语句这它给修改到外层函数作用域里面这个变量,实现一个带记忆功能的一个函数

下面是一个小甲鱼在舞台上移动的程序,在Python的编辑模式下编写:
origin = (0,0)          #这个是原点
legal_x = [-100,100]    #限定x轴的移动范围
legal_y = [-100,100]    #限定y轴的移动范围

def create(pos_x=0,pos_y=0):
    def moving(direction,step):
        nonlocal pos_x,pos_y
        new_x = pos_x + direction[0] * step
        new_y = pos_y + direction[1] * step

        if new_x < legal_x[0]:
            pos_x = legal_x[0] - (new_x - legal_x[0])
        elif new_x > legal_x[1]:
            pos_x = legal_x[1] - (new_x - legal_x[1])
        else:
            pos_x = new_x

        if new_y < legal_y[0]:
            pos_y = legal_y[0] - (new_y - legal_y[0])
        elif new_y > legal_y[1]:
            pos_y = legal_y[1] - (new_y - legal_y[1])
        else:
            pos_y = new_y

        return pos_x,pos_y

return moving
上面这个程序是在编辑模式下完成的,在交互模式下,点击右上角的“file”,选择”New File“,会弹出新的窗口就是Python的编辑窗口,编辑好后,在编辑模式下,先点击file中的“save“保存为.py文件,再在编辑模式下点击菜单中的run下的“run module”,运行后,再在Python的交换模式下查看运行效果,并且输入相应的交换命令,以下是在交互模式下完成的,IDLE Shell3.12.1
==================== RESTART: D:/谷兴武/创客/python学习/角色在舞台上移动.py ===================
move = create()
print("向右移动20步后,位置是:",move([1,0],20))
向右移动20步后,位置是: (20, 0)
print("向上移动120步后,位置是:",move([0,1],120))
向上移动120步后,位置是: (20, 80)
print("向右下角移动88步后,位置是:",move([1,-1],88))
向右下角移动88步后,位置是: (92, -8)

关注公众号

相关侵权、举报、投诉及建议等,请发 E-mail:admin@discuz.vip

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.|鄂ICP备13007585号-4

在本发帖
关注公众号
QQ客服返回顶部