闭包(Closure)和匿名函数

闭包(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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值