• Python闭包及其作用域


    Python闭包及其作用域

    关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记

    如果在一个内部函数里,对一个外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被称为闭包(closure),而这个被内部函数引用的变量则被成为自由变量

    闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量

    命名空间和作用域

    我们把命名空间看做一个大型的字典类型(Dict),里面包含了所有变量的名字和值的映射关系。在 Python 中,作用域实际上可以看做是“在当前上下文的位置,获取命名空间变量的规则”。在 Python 代码执行的任意位置,都至少存在三层嵌套的作用域:

    1. 最内层作用域,最先搜索,包含所有局部变量(Python 默认所有变量声明均为局部变量)
    2. 所有包含当前上下文的外层函数的作用域,由内而外依次搜索,这里包含的是非局部也非全局的变量
    3. 一直向上搜索,直到当前模块的全局变量
    4. 最外层,最后搜索的,内置(built-in)变量
     scopes = {
        "local": {"locals": None,
                 "non-local": {"locals": None,
                              "global": {"locals": None,
                                        "built-in": ["built-ins"]}}},
    }
    

    除了默认的局部变量声明方式,Python还有globalnonlocal两种类型的声明(nonlocal是Python3.x之后才有的),其中nonlocal是指最内层之外,global以内的变量。必须强调的是,最内层局部作用域对外层作用域的变量只有只读(read-only)的访问权限。比如下列的例子

    x = 100
    def main():
        x += 1
        print (x)
    main()
    
    ---------------------------------------------------------------------------
    UnboundLocalError Traceback (most recent call last)
    <ipython-input-2-9ed43e483a17> in <module>()
          3 x += 1
          4 print(x)
    ----> 5 main()
    <ipython-input-2-9ed43e483a17> in main()
          1 x = 100
          2 def main():
    ----> 3 x += 1
          4 print(x)
          5 main()
    UnboundLocalError: local variable 'x' referenced before assignment
    

    这里抛出UnboundLocalError,是因为main()函数内部的作用域对于全局变量x仅有只读权限,想要在main()中对x进行改变,不会影响全局变量,而是会创建一个新的局部变量,显然无法对还未创建的局部变量直接使用x += 1, 因为x未绑定到任何对象上。如果想要获得全局变量的完全引用,则需要global声明:

    x = 100
    def main():
        global x
        x += 1
        print(x)
    main()
    print(x) # 全局变量已被改变
    
    # result: 
    #  101
    #  101
    

    闭包

    闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量
    看了上面的Python作用域规则后,我们可以仿照JavaScript写一个计数器的闭包:

    """
    /* JavaScript Closure example */
    var inc = function(){  
      var x = 0;
      return function(){
        console.log(x++);
      };
    };
    var inc1 = inc()
    var inc2 = inc()
    """
    
    # Python
    def inc():
        x = 0
        def inner():
            nonlocal x
            x += 1
            print(x)
        return inner
    inc1 = inc()
    inc2 = inc()
    inc1()
    inc1()
    inc1()
    inc2()
    
    
    # result:
    #    1
    #    2
    #    3
    #    1
    

    在这里,全局环境下不能获取到inc()中的局部变量x的,但是我们返回了inc()内部函数inner(),而inner()inc()中的局部变量是有访问权限的。也就是说inner()inc()局部作用域打包发送给了inc1inc2,从而使他们各自独立拥有了一块封闭起来的作用域,不受其他运行环境和全局变量的影响,因此称之为闭包。

    上述代码中inc1和inc2各自有一块封闭起来的作用域,可以通过Online Python Tutor 可视化运行工具看相应的运行结果

  • 相关阅读:
    Java Web项目开发中常见路径获取方法
    Genymotion模拟器连接不上开发服务器解决办法
    百度鹰眼轨迹管理台部署到本地或者服务器上
    解决Hibernate4执行update操作,不更新数据的问题
    后台发送http请求通用方法,包括get和post
    Java后端发出post请求带参数并接收返回的json
    $.ajax()方法详解
    常见异常及解决办法
    jQuery通过地址获取经纬度demo
    python 导入模块与使用
  • 原文地址:https://www.cnblogs.com/pluviophile/p/7441851.html
Copyright © 2020-2023  润新知