前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python的闭包

Python的闭包

作者头像
ZONGLYN
发布2019-08-08 10:10:03
7250
发布2019-08-08 10:10:03
举报
文章被收录于专栏:程序萌部落程序萌部落
地位:
代码语言:javascript
复制
闭包 和函数有关系
解释:
代码语言:javascript
复制
python中一切皆对象:
函数可以赋值给变量,例如 a = def func(), 
可以把函数当做参数,传入一个函数
可以把函数当做一个函数的返回结果
示例:
代码语言:javascript
复制
Python中允许的正确的调用方法:
    def curve_pre():
        def curve():
            print('This is a funcion')
        return curve        #函数作为返回值
    func = curve_pre()
    func()
    #产生调用,输出 This is a funcion
将上述示例扩展为闭包:
代码语言:javascript
复制
注意:
    闭包内的变量与闭包外的变量没有关系
示例:
    def curve_pre():
        a = 25              #a在curve外部
        def curve(x):
            return a*x*x
        return curve        #函数curve作为返回值
    func = curve_pre()
    print(func(2))          #打印100
外部变量对一般函数的影响:
    a = 10
    def f(i):
        return a*i
    print(f(2))             #打印20
    函数外面的a影响到了函数内a的值
外部变量对闭包的影响:
    a = 10 
    print(func(2))          #打印100
    调用外面的a没有影响到函数内a的值,def curve(x)内的a仍然是def curve_pre()内的a的值
    上述就是闭包的现象
闭包定义:
代码语言:javascript
复制
由函数以及函数定义时外部的变量构成的整体,叫闭包
闭包 = 函数 + 原函数所处环境的变量(原函数外部)
注意:
代码语言:javascript
复制
上述函数所处环境的变量不能是全局变量,即:至少需要两个结构体嵌套

闭包内的环境变量:
    保存在curve_pre().__closure__内
    print(func.__closure__)
    #输出:(<cell at 0x0000000001158CA8: int object at 0x00000000539604D0>,)
    print(func.__closure__[0].cell_contents)
    #输出:25
注意:
代码语言:javascript
复制
单一函数 + 不同的外部变量 = 多种不同的闭包(类似设计模式的工厂模式)
闭包的调用方式:
代码语言:javascript
复制
正常非闭包函数的调用:
代码:
    def func1():
        a = 10
        def func2():
            a = 20
            print("func2's a = ",a) # 20    运行顺序:2
        print("func1's a = ",a)     # 10    运行顺序:1
        func2()
        print("func1's a = ",a)     # 10    运行顺序:3

    func1()
注意:
    上述是一个函数的调用,不是一个闭包,可以使用__closure__来判断是否为闭包

测试是否是闭包:
    def func1():
        a = 10
        def func2():
            a = 20
            return a
        return func2
        func2()
    func1()
    f = func1()
    print(f.__closure__) #输出:None
原因:
    func2中的a被当做了局部变量,此时func2函数内并没有产生对外部变量的引用!
    所以,并没有构成一个闭包

修改为闭包的方式:
    def func1():
        a = 10
        def func2():
            #a = 20        将局部变量a注释
            c = a * 20
        return func2
        func2()
    func1()
    f = func1()
    print(f.__closure__) 
    #输出:(<cell at 0x0000000001108CA8: int object at 0x00000000539602F0>,)
成为闭包的原因:
    将func2中的局部变量a去掉后,只要func2中产生对外部变量a的使用,就可以被作为闭包
    闭包一定要引用外部环境的变量
闭包的应用:
代码语言:javascript
复制
要求:
    对于x,y    按顺序x=3,y=3;x=5,y=8;x=6,y=14
本质:
    需要对中间变量进行保存
非闭包实现:(失败)

    origin = 0
    def walk(step):
        new_pos = origin + step     #这一步origin是外面的全局变量
        origin = new_pos            
        #此处的赋值会出错,因为如果函数内部有赋值操作,那么origin会变成局部变量,从而导致上一句中找不到origin的定义
        return origin
    print(walk(3))
    print(walk(5))
    print(walk(6))

上述代码修改为:(借助global,成功)
    origin = 0
    def walk(step):
        global origin           #显式的声明全局变量之后,就不会讲origin作为局部变量
        new_pos = origin + step      
        origin = new_pos             
        return origin
    print(walk(3))  #3
    print(walk(5))  #8
    print(walk(6))  #14

闭包方式:(失败)
    origin = 0
    def func1(pos):
        #pos成为了环境的变量
        def walk(step):
           new_pos = pos + step 
           pos = new_pos    
           #此处报错UnboundLocalError: local variable 'pos' referenced before assignment
           return new_pos
        return walk
    tour = func1(origin)
    print(tour(3))  #3
    print(tour(5))  #8
    print(tour(6))  #14

修改为:(借助nonlocal,成功)
    origin = 0
    def func1(pos):
        #pos成为了环境的变量
        def walk(step):
           nonlocal pos     #显式声明pos是一个本地变量
           new_pos = pos + step 
           pos = new_pos    
           #此处报错UnboundLocalError: local variable 'pos' referenced before assignment
           return new_pos
        return walk
    tour = func1(origin)
    print(tour(3))  #3
    print(tour.__closure__[0].cell_contents)  #3
    print(tour(5))  #8
    print(tour.__closure__[0].cell_contents)  #8
    print(tour(6))  #14
    print(tour.__closure__[0].cell_contents)  #14

使用闭包的优点:(函数式编程)
    没有使用全局变量origin,所有的变量操作均在闭包内部
    闭包+nonlocal关键字可以完成中间变量的记录,打印__closure__[0].cell_contents也会发现,闭包确实记录了中间变量
闭包的扩展:
代码语言:javascript
复制
可以实现设计模式中的;工厂模式
闭包内的变量会常驻内存,使用时要注意
闭包不是函数式编程的全部,只是一种体现
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 地位:
  • 解释:
  • 示例:
  • 将上述示例扩展为闭包:
  • 闭包定义:
  • 注意:
  • 注意:
  • 闭包的调用方式:
  • 闭包的应用:
  • 闭包的扩展:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档