zoukankan      html  css  js  c++  java
  • Python自由之路(五)Pyhton 闭包

    如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).闭包在函数式编程中是一个重要的概念。语法上看比较简单,但是用处却是相当广泛的。
    在Python 2.1版本以前,只有全局域和局部作用域,而在2.1以后的版本中我们可以使用静态嵌套域,如像下面这样的嵌套函数中,在以前,内部函数是不能访问外部函数作用域中的变量的。
    def foo():
        m = 3
        def bar():
            n = 4
            print m + n
        print m
     bar()
    而在现在的版本中可以完美运行,而bar()中的 m 就是一个既不属于全局域又不属于局部域的闭包变量,它存活在一个函数的名称空间和作用域---嵌套作用域。而在闭包中对嵌套作用域中的访问规则与上面讨论的Global是一样的。即在对闭包变量 m 的重新声明之前引用 m 都会引发异常
    def foo():
        m = 3
        def bar():
            print m  #UnboundLocalError
            m=4
            print m
     bar()
    UnboundLocalError: local variable 'm' referenced before assignment
    为什么会这样呢?其实是因为m的类型有关,我们知道Pyhton中的基本数据类型分为可变和不可变,对于不可变类型的赋值,其实是重新定义一个新的变量对象,并深拷贝原对象到新对象,参考str类型说明。 如果将上面的 m 声明成可变类型list,那就不会产生这个异常了。
     def foo():
          m = [3]
          def bar():
              print m[0]
              m[0]=4
             print m[0]
          bar()
    关于可变类型与不可变类型的说明,这里就不展开说了,大家可以看API Document

    下面举一个闭包的实际例子:
    def hellocounter (name):
        count=[0]
        def counter():
            count[0]+=1
            print 'Hello,',name,',',str(count[0])+' access!'
        return counter

    hello = hellocounter('ysisl')
    hello()
    hello()
    hello()

    Console output:
     Hello, ysisl , 1 access!
     Hello, ysisl , 2 access!
     Hello, ysisl , 3 access!
    这个例子中,hellocounter(name)返回了一个内部函数counter的引用,就像C++中指向函数的指针一样,我们把这个引用用一个变量hello来保存,那么这个变量就代表了这个counter函数,为什么对hello()的反复调用能保持闭包变量count的自增,而不是释放后再重新分配?因为count不是counter的局部变量,它是一个在hellocounter()范围内游离于counter之外的变量,只有当hellocounter(name)被调用时,count才被重新分配新的内存地址。

  • 相关阅读:
    nodejs async waterfull 小白向
    nodejs async series 小白向
    MySQL 分区介绍总结
    cocos2d-x 一些实用的函数
    LeetCode(61)-Valid Palindrome
    ganglia错误解决
    (6)uboot具体解释——关闭缓存和mmu
    Linux下设置MySQL不区分大写和小写
    火狐与IE的7个JavaScript差异
    商业研究(8):汽车交通
  • 原文地址:https://www.cnblogs.com/ysisl/p/1548075.html
Copyright © 2011-2022 走看看