首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python和Scala里的闭包

在函数式编程里,闭包(closure)是绕不过的话题,它的实现基础来源于变量作用域和一等函数。也正是因为如此,我们可以进一步把代码块抽象,Python也诞生了装饰器。

1.闭包的概念:

闭包源于λ表达式,它的概念核心分为两块,1.上下文环境 2.控制流程。进一步地说,闭包是绑定了自由变量的函数实例。通常来讲,闭包地实现机制是定义一个特殊的数据结构,保存了函数地址指针与闭包创建时的函数的词法环境以及绑定自由变量。对于闭包最好的解释,莫过于《流程的Python》里给出的“它是延伸了作用域的函数,其中包括函数定义体引用,但是不在定义体定义的非全局变量。核心在于闭包能够访问定义体之外定义的非全局变量。”

2.闭包的具体实现:

首先我们需要区分什么是自由变量和绑定变量。自由变量指的是函数自身没有提供这个参数,而绑定变量则是它在函数上下文有着明确的含义。例如:

Scala

Python

我们可以注意到这里的more就是自由变量,x是匿名函数的绑定变量。x很明确的是由匿名函数定义了,more并没有绑定在匿名函数里面。在Scala里,匿名函数本身没有给予more任何含义,但是只要预先定义了more变量,则add函数可以正常运行了。而Python因为是在运行期才会检查more是否存在,所以函数可以正常的定义,而在后面我们赋值给了more,increase函数便正常运行了。

此时的add/increase函数被称为闭包,它“捕获”自身的自由变量从而“闭合”该匿名函数。接下来看看Scala和Python有什么特别之处吧!

Scala:

在Scala里“捕获”的是变量本身,而不是变量本身引用的值。

当然,反过来也是成立的,闭包也可以修改其自由变量

那么问题来了,如果more这个变量随着程序的运行被修改了很多次,那么闭包会选择哪一个呢?Scala的答案是,闭包被创建时这个变量最新的那个。(根据定义函数的词法作用域计算自由变量)

Python:

因为Python的函数本身是对象,它提供了很多方法查看函数的参数,例如我们可以查看上面例子的变量:

在__code__里可以清楚的看到more是自由变量,而x是绑定变量。而more绑定在__closure__方法里。

Python在每一次创建闭包时,自由变量都会重新创建,而不会保存,在Python3引入了nonlocal声明解决这个问题。在Python里,由闭包引申了装饰器的概念。这是因为装饰器依赖于内部函数的嵌套。例如:

这里的target会作为参数传入deco,而deco返回的是inner函数。在name里,target这个名字并不会存在了,取而代之的是inner函数。

一个小的知识点,装饰器在导入模块时会立即运行,而被装饰的函数则会在明确调用时才会运行。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180320G1MWOK00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券