zoukankan      html  css  js  c++  java
  • Python:闭包

    闭包(Closure)

          在一个函数内部定义另一个函数,然后内部函数用到外部函数的变量,把内部函数以及用到的外部变量,合称闭包。

    首先复习一下

    命名空间与作用域

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

    • local            最内层作用域,最早搜索,包含所有局部变量**(Python 默认所有变量声明均为局部变量)**
    • non-local    所有包含当前上下文的外层函数的作用域,由内而外依次搜索,这里包含的是非局部也非全局的变量
    • global         一直向上搜索,直到当前模块的全局变量
    • built-in        最外层,最后搜索的,内置(built-in)变量

           在任意执行位置,可以将作用域看成是对下面这样一个命名空间的搜索:

    
    
    scopes =
    { "local": {"locals": None, "non-local": {"locals": None, "global": {"locals": None, "built-in": ["built-ins"]}}}, }
     

           除了默认的局部变量声明方式,Python 还有globalnonlocal两种类型的声明(nonlocal是Python 3.x之后才有,2.7没有),其中 global 指定的变量直接指向(3)当前模块的全局变量,nonlocal则指向(2)最内层之外,global以内的变量。这里需要强调指向(references and assignments)的原因是,普通的局部变量对最内层局部作用域之外只有**只读(read-only)**的访问权限,比如下面的例子:

    >>>x = 100  #该全局变量可被所有函数调用
    >>def main():
        x += 1
        print(x)
    
    >>>main()
    Traceback (most recent call last):
      File "<pyshell#50>", line 1, in <module>
        main()
      File "<pyshell#49>", line 2, in main
        x += 1
    UnboundLocalError: local variable 'x' referenced before assignment

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

    >>>x = 100
    >>>def main():
        global x
        x += 1
        print(x)
        
    >>>main()
    print(x) # 全局变量已被改变,后面的全局变量x都为101
    101

    Python闭包

    demo:

    # 外部函数
    def fun():
        print('outer')
        # 内部函数
        def fun_in():
            print('inner')
        return fun_in
    
    # 调用外部函数
    fun()    
    a = fun()
    print(a) 
    # 调用内部函数
    a()       
    
    
    # 输出结果
    outer
    <function fun.<locals>.fun_in at 
    inner

    再写个闭包调用时机的小例子

    def fun():
        print('---1---')
        def fun_in():
            print('---2---')
        print('---3---')
        return fun_in   # 注意没有小括号
    
    # fun()
    # 输出结果
    # ---1---
    # ---3---
    
    # 调用 fun_in才输出---2---
    a = fun()
    print('-------')
    a()
    
    #输出结果
    ---1---
    ---3---
    -------
    ---2---

    闭包在内存中的状态

    在python函数的使用里,当函数调用结束后,函数对应的内存空间被释放,里面所有东西都被清空

    但在闭包中例外,因为函数里面还有东西(内部函数)被引用了。因此外部函数的空间就没被释放(涉及到python回收机制的知识:引用计数)

    如果再次调用这个函数,就还会重新生成一份新的内存空间

    def fun(number):
        def fun_in(number_in):
            print('number = %d, number_in = %d' % (number, number_in))
            return number + number_in
        return fun_in
    
    a1 = fun(3)
    print(a1(8)) # 11 = 3 + 8
    
    a2 = fun(5)
    print(a2(8)) # 13 = 5 + 8
    
    print(a1(9)) # 12 = 3 + 9
    
    print(a2(9)) # 14 = 5 + 9

    所以,当通过a1去调用内部函数,和通过a2去调用内部函数的时候,实际上是在不同的内存空间上去跑的。

    Github地址:https://github.com/kumataahh
  • 相关阅读:
    bzoj 4883 [Lydsy1705月赛]棋盘上的守卫——并查集(思路!)
    洛谷 1979 华容道——最短路+dp
    51nod 1443 路径和树——最短路生成树
    hdu 2222 Keywords Search——AC自动机
    bzoj 2067 [Poi2004]SZN——二分+贪心
    洛谷 1084 疫情控制——二分答案+贪心(贪心思路!)
    CF 1042A Benches——二分答案(水题)
    洛谷 1314 聪明的质监员——二分答案
    洛谷P3690 LCT模板
    bzoj1875 [SDOI2009]HH去散步——矩阵快速幂
  • 原文地址:https://www.cnblogs.com/kumata/p/9059878.html
Copyright © 2011-2022 走看看