Python 闭包

本文是我在学习时的篇笔记,示例代码可能岑在直接引用学习资料的情况。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#========================================================================

'''
Python 函数可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,
便会产生闭包问题。
'''

'''
闭包:是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)
    (想想Erlang的外层函数传入一个参数a, 内层函数依旧传入一个参数b, 内层函数使用a和b,
     最后返回内层函数)
'''
def ExFunc(a):
  def InsFunc(b):
    print "a:",a,"  b:",b
    return a + b
  return InsFunc(3)    ## 这里返回的是函数的值

# if __name__ == "__main__":
#   ret = ExFunc(5)
#   print "ret:",ret,"   type(ret)",type(ret)
#   print InsFunc(3)    ## 会报错
'''
OUT PUT:
a: 5   b: 3
ret: 8    type(ret) 
NameError: name 'InsFunc' is not defined
这里可以看出两点:1.在函数ExFunc内部定义的函数InsFunc可以访问到外层函数的局部变量。
                2.InsFunc函数的作用域仅在外层函数的函数体内。
'''

#------------------------------------------------------------------
'''
    在函数式语言中,当内嵌函数体内引用到体外的变量时,将会把定义时涉及到的引用环境
和函数体打包成一个整体(闭包)返回。
'''
def FuncOut(num):
  sum = num
  def FuncIn(num2=0):
    print "num2:",num2,"  sum:",sum
    ## sum = sum + num2  ## 这里这样写是不行的,因为内部如果出现与外部同名参数,
                         ## 则不再用外部的参数。(类比全局变量和局部变量)
    ## sum += num2       ## 同上
    return sum + num2
  return FuncIn
# if __name__ == "__main__":
#   f1 = FuncOut(10)
#   print "f1:",f1,"   type(f1):",type(f1)    ## f1:     type(f1): 
#   print "f1():",f1(9)               ## f1(): num2: 9   sum: 10 \n 19
#   f2 = f1(8)                        ## num2: 8   sum: 10
#   print "f2():",f2                 ## f2(): 18
#   f3 = FuncOut(5)
#   print "f3():",f3(7)               ## f3(): num: 5   sum2: 7 \n 12
#   print f3.__closure__
#   print f3.__closure__[0].cell_contents
'''
OUT PUT:
f1:     type(f1): 
f1(): num2: 9   sum: 10
19
num2: 8   sum: 10
f2(): 18
f3(): num2: 7   sum: 5
12
   如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么
函数就被认为是闭包(senior)
'''

#----------------------------------------------------------------------
'''
注意事项:
1.闭包中不能修改外部作用域的局部变量。(如上,不能在FuncIn中修改FuncOut中的局部变量sum)
  以下是一段经典的错误代码:
def foo():
    a = 1
    def bar():
        a = a + 1
        return a
    return bar
  这段程序的本意是要通过在每次调用闭包函数时都对变量a进行递增的操作。但在实际使用时,
调用 foo()时,python会导入全部的闭包函数体bar()来分析其的局部变量,python规则指定
所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号"="的左面,被
python认为是bar()中的局部变量。再接下来执行print c()时,程序运行至a = a + 1时,
因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的
值,结果找不到,就会报错。
  解决方式:
'''
def foo():
    a = [1]
    def bar():
        a[0] = a[0] + 1
        return a[0]
    return bar
# if __name__ == "__main__":
#   c = foo()
#   print c()
#   print c()
'''
注意事项:
2.由于python的函数只有在执行时才会去找函数体里的变量的值,而引起的错误
'''
# if __name__ == "__main__":
#   flist = []
#   for i in range(3):
#     def foo(x): print x + i
#     flist.append(foo)
#   for f in flist:
#     f(0)
'''
    期待执行结果应该是0,1,2,但是实际的结果是2,2,2。这是由于当把函数加入flist列表里时,
python还没有给i赋值,只有当执行时,再去找i的值,这时在第一个for循环结束以后,i的值是2。
    解决:
'''
# if __name__ == "__main__":
#   flist = []
#   for i in range(3):
#     def foo(x,y=i): print x + y   ## 这样会在定义时,将y的默认值设置为i当时的值
#     flist.append(foo)
#   for f in flist:
#     f(0)

你可能感兴趣的:(Python,闭包,函数体内定义函数,python语言基础)