闭包(Closure)
定义
闭包是由函数与其相关的引用环境组合而成的实体.通俗来讲就是:在一个内部函数里,对在外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 看个例子:
>>> def funA(x):
... def funB(y): return x + y
... return funB
...
>>> funA
<function funA at 0x7fdfad04c5f0>
>>> funA(10)
<function funB at 0x7fdfad04c668>
>>> funA(10) == funA(10)
False
>>> funA(10)
<function funB at 0x7fdfad04c7d0>
>>> funA(10)
<function funB at 0x7fdfad04c6e0>
#每次运行都会返回一个新函数所以内存地址会不一样
>>> i = funA(10)
>>> i
<function funB at 0x7fdfad04c6e0>
>>> i(9)
19
它有这样的特性:
- 函数是一类值(First-class value),即函数可以作为另一个函数的返回值或参数,还可以作为一个变量值.
- 函数可以嵌套定义,即在一个函数内部可以定义另一个函数
- 嵌套的函数可以访问其父作用域中的数据
理解闭包必须知道python的作用域规则:
可以用LEGB来总结python的作用域规则:当一个变量被访问的时候,Python会按LEGB顺序来搜索变量:
注意
访问规则只对普通变量有效,访问对象的属性与此无关.
- L. Local :局部作用域,即函数中定义的变量(没有global声明)
- E. Enclosing: 嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,通常也称为
non-local作用域. - G. Global(module): 在模块级别定义的全局变量(如果在函数内修改它,需要global声明)
- B.Built-in: built-in模块里面的变量,也就是内建函数,比如 int,Exception等.
此规则有一个重要的限制:
一个不在局部作用域里的变量默认是只读的,如果试图为其绑定一个新的值,Python会认为是在当前局部作用域里创建一个新的变量.
>>> def count():
... fs = []
... for i in range(1,4):
... def f():
... return i*i
... fs.append(f)
... return fs
...
>>> f1,f2,f3 = count()
>>> f1()
9
>>> f2()
9
>>> f3()
9
可能有人认为这段代码执行的结果是1,4,9,但是实际结果是9,9,9.这是因为当函数f被加入fslist的时候还没有执行,只是将函数装进了list里面.当函数count函数被调用后才开始执行,去寻找i的值是多少,这时候for循环结束后得到的i是3所以上述代码的结果都为9.有点难理解来翠花上个例子~
>>> for i in range (1,4):
... print i
...
1
2
3
#for循环结束,但是i不会被销毁,它被最后for循环最后的遍历出的结果`3`赋值.
>>> def count():
... fs = []
... for i in range(1,4):
... def f(x=i): return x*x
... fs.append(f)
... return fs
...
>>> y1,y2,y3 = count()
>>> y1()
1
>>> y2()
4
>>> y3()
9
>>> def count():
... fs = []
... for i in range(1,4):
... def f(x=i): return x*x, i
... fs.append(f)
... return fs
...
>>> y1,y2,y3 = count()
>>> y3()
(9, 3)
>>> y2()
(4, 3)
>>> y1()
(1, 3) #i返回的结果都为3,但是x是变化的,x在每次循环的时候被赋值,然后输出结果.
匿名函数
定义
有时候我们不需要函数名,直接传入匿名函数更方便.
关键字lambad表示匿名函数,冒号:前面的是参数,后面的是表达式.表达式将计算结果传给参数.
比如:
>>> map(lambda x: x*x, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
#等价于
>>> def f(x):
... return x*x
...
>>> map(f, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
是不是感觉方便很多~
怎么调用匿名函数呢?
既然是函数就可以被当作一个对象赋值给一个变量,我们可以这样做:
>>> i = lambda x: x*x
>>> i(8)
64
本文详细介绍了Python中的闭包概念及其工作原理,并通过实例解释了闭包的使用方式。此外,还介绍了如何使用lambda表达式创建匿名函数,以及它们在实际编程中的应用。
532

被折叠的 条评论
为什么被折叠?



