Python  闭包 (Closure)

这里介绍一下python 的闭包

基本概念

闭包(closure)是函数式编程的重要的语法结构。

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。

在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。

函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。

闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

不同的语言实现闭包的方式不同。Python以函数对象为基础,

为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。

Python一切皆对象,函数这一语法结构也是一个对象。

在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

函数对象的作用域

和其他对象一样,函数对象也有其存活的范围,也就是函数对象的作用域。

函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。

比如下面代码,我们在next函数的隶属范围内定义的函数test,就只能在test的隶属范围内调用。

def test():

    def next():
print('next') print('test') test() # 执行结果
> test

再看下面代码

def test():

    def next():
print('next')
next()
print('test')
next()
test() # 执行结果
> next
> test
> next

引入闭包

函数是一个对象,所以可以作为某个函数的返回结果。

def hello(greet):

    def setName(name):
print(greet,name)
return setName Hello = hello("Good Morning") Hello('Yang') print(dir(Hello)) print(Hello.__closure__) print(Hello.__closure__[0].cell_contents) print(Hello.__name__) print(id(Hello)) Hellob = hello("Good Afternoon") Hellob('Yang')
print(Hello.__name__) print(id(Hellob)) # 执行结果
#> Good Morning Yang
#> ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
#> (<cell at 0x0000026D9A8078B8: str object at 0x0000026D9A966370>,)
#> Good Morning
#> setName
#> 1779595040560
#> Good Afternoon Yang
#> setName
#> 1779595040696

闭包只是在表现形式上跟函数类似,但实际上不是函数。

从代码的结果中可以看到,闭包在运行时可以有多个实例,不同的引用环境变量(这里就是greet变量)和相同的函数(这里就是setName)组合可以产生不同的实例。

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是Good Morning,也就是我们创建闭包时的环境变量greet的取值。

Python中怎么创建闭包

在Python中创建一个闭包可以归结为以下三点:

  • 闭包函数必须有内嵌函数
  • 内嵌函数需要引用该嵌套函数上一级中的变量
  • 闭包函数必须返回内嵌函数

通过这三点,就可以创建一个闭包

闭包实例

def closureFun():
'''闭包'''
a = 5
def add(x): # 1 闭包函数必须有内嵌函数
return x + a # 内嵌函数需要引用该嵌套函数上一级中的变量 a
return add # 闭包函数必须返回内嵌函数
print(locals()) c = closureFun() # 实例化函数 closureFun 返回 函数add
sum = c(6) # 调用add ,并传参 ,此时返回 x + a = 6 + 5 = 11 print(sum) # print(globals())

Python中的内建函数locals()和globals()可以用来查看不同namespace中定义的元素。

总结

本文介绍了如何通过Python创建一个闭包,以及Python创建的闭包是如何工作的。

Python 闭包(Closure)的更多相关文章

  1. python 闭包(closure)

    闭包的定义: 闭包就是一个函数,这个函数可以记住封闭作用域里的值,而不管封闭作用域是否还在内存中. 来一个例子: def happy_add(a): print 'id(a): %x' % id(a) ...

  2. python闭包closure

    在讨论闭包之前,先总结一下python的命名空间namespace,一般的语言都是通过namespace来识别名字标识,无论是变量,对象,函数等等.python划分3个名字空间层次,local:局部, ...

  3. Python闭包Closure 2

    由于Python中,变量作用域为LEGB,所以在函数内部可以读取外部变量,但是在函数外不能读取函数内的变量.但是出于种种原因,我们需要读取函数内的变量时候怎么办?那就是在函数内在加一个函数. def ...

  4. python 闭包 Closure 函数作为返回值

    一.函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. >>> def lazy_sum(*args): ... def sum(): ... ax = ...

  5. python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)

    1.函数对象 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函 ...

  6. 【Python】闭包Closure

    原来这就是闭包啊... 还是上次面试,被问只不知掉js里面的闭包 闭包,没听过啊...什么是闭包 回来查了下,原来这货叫闭包啊...... —————————————————————————————— ...

  7. Python 闭包

    什么是闭包? 闭包(closure)是词法闭包(lexical closure)的简称.闭包不是新奇的概念,而是早在高级程序语言开始发展的年代就已产生. 对闭包的理解大致分为两类,将闭包视为函数或者是 ...

  8. Python闭包与javascript闭包比较

    实例一 python def line_conf(): def line(x): return 2*x+1 print(line(5)) # within the scope     line_con ...

  9. Python闭包与函数对象

    1. Python闭包是什么 在python中有函数闭包的概念,这个概念是什么意思呢,查看Wikipedia的说明如下: “ In programming languages, closures (a ...

随机推荐

  1. linux判断日志文件大小进行清理

    脚本写了一个死循环,根据nohup产生的日志多大, 这里表示日志超过500M之后清理, 具体数字可自定义 睡眠数可自定义 #!/usr/bin/bash while true do s=`du -k ...

  2. phpstudy手动把mysql数据库从5.5.56升级到5.6.41

    查看mysql版本: mysql> select version(); 1.关闭mysql,把原来的D:/phpStudy/PHPTutorial/mysql改名为MySQL_5.5.53作为备 ...

  3. 【TensorFlow】tf.nn.max_pool实现池化操作

    max pooling是CNN当中的最大值池化操作,其实用法和卷积很类似 有些地方可以从卷积去参考[TensorFlow]tf.nn.conv2d是怎样实现卷积的? tf.nn.max_pool(va ...

  4. 前后台分离开发--文件上传与下载,cookie,session

    一.前后台分离开发的概念 ''' 1. 前台页面运行在前台服务器上,负责页面的渲染(静态文件的加载)与转跳 2. 后台代码运行在后台服务器上,负责数据的处理(提供数据请求的接口) ''' #如果没有前 ...

  5. libcurl 设置代理,通过Fiddler可以进行抓包

    转载:https://blog.csdn.net/jaryguo/article/details/53021923 转载:https://www.cnblogs.com/miantest/p/7289 ...

  6. HIHOcoder 1403 后缀数组一·重复旋律

    思路 后缀数组的板子题,注意后缀数组的rank[]数组是通过位置找到对应排名的,sa[]是通过排名找到位置的,height[i]记录的是sa[i]和sa[i+1]之间的lcp 不要写错了就行了 代码 ...

  7. 题解——loj6281 数列分块入门5 (分块)

    分块 若块内最大值为0或1,则不用再开方 然后暴力修改 可以证明,如果开方后向下取整,则最多开方4次一个数就会变成0或1 #include <cstdio> #include <cm ...

  8. 题解——洛谷P2827 NOIP提高组 2016 蚯蚓

    队列模拟 详细题解待填坑 #include <cstdio> #include <algorithm> #include <queue> #include < ...

  9. Vue的生命周期(钩子函数)

    Vue一共有10个生命周期函数,我们可以利用这些函数在vue的每个阶段都进行操作数据或者改变内容. 其实在Vue的官网有一张图已经很好的诠释了生命周期,我在这里就不再多讲了,直接贴图,然后上程序代码. ...

  10. maven下载jar包下载不下来的解决方法

    转载请注明出处: 在eclipse中安装了maven插件,项目在运行的时候,一直通过pom.xml文件下载jar包,一直下载不下来, 在更新maven库时,如果网络问不定或者是一些自己手动安装到本地m ...