闭包函数初探

通常我们定义函数都是这样定义的

def foo():pass

其实在函数式编程中,函数里面还可以嵌套函数,如下面这样

def foo():print("hello world in foo")def bar():print("hello world in bar")

此时我们调用foo函数,执行结果会是什么样子的呢??

hello world in foo

结果如上所示,只会执行foo函数的第一层函数,bar函数是不会被执行的。为什么呢

实际上来说,不管函数写在哪个部分,那都只是定义了一个函数,只有这个函数被调用,函数内部的语句才会被执行

在上面的例子中,bar函数虽然在foo函数内部定义了,但是并没有被执行,所以bar函数是不会被执行的

这样说来,定义在一个函数内部的函数就没什么作用了吗??其实不是这样的。

来看下面的例子,把bar函数作为一个值返回给foo函数,来看执行过程

def foo():print("hello world in foo")def bar():print("hello world in bar")return barf1=foo()
print(f1)

此时,由于bar函数作为一个返回值被返回给了foo,所以foo函数执行结果是有返回值的

此时定义一个变量f1来接收foo函数的执行返回结果,然后打印f1

返回的结果如下

hello world in foo
<function foo.<locals>.bar at 0x0000000002941A60>

可以看到首先打印了foo函数中定义的一个print语句,接着打印的是foo函数中包含的bar函数的内存地址

既然是一个函数的内存地址,当然可以加括号来执行这个函数

def foo():print("hello world in foo")def bar():print("hello world in bar")return barf1=foo()
f1()

此时,这段代码的执行结果为:

hello world in foo
hello world in bar

两个print语句都被打印出来了。

在上面的例子里,首先定义了一个函数foo,接着在foo函数内部又嵌套定义了一个函数bar,然后返回函数bar的函数名,这就是闭包函数的定义方式。

其实,闭包的定义就是一个函数内部又嵌套了一个函数

来看下面的这段代码

    def foo():print("hello world in foo")name="python"def bar():print(name)print("hello world in bar")return barf1=foo()f1()

在上面的例子里,在外层函数中定义了一个变量name,然后在内层函数中打印这个变量name

此时执行上面的代码,在打印name这个变量的时候,会先在bar函数内部查找name这个变量,但是bar函数里面是没有name这个变量的,

此时根据python查找变量的LEGB法则,会到bar函数的外面一层去继续查找name这个变量,此时可以找到name这个变量

所以这里打印的foo函数中定义的name的值

执行上面的代码,打印结果如下

hello world in foo
python
hello world in bar

这里要记住很重要的一点就是:

内层函数引用了外层函数的局部变量

来分析下上面的例子中程序的执行过程:

首先运行foo函数,foo函数的执行结果是返回bar的函数名,此时又把foo函数的执行结果定义给了变量f1,
所以此时f1就等于bar这个函数的内存地址,然后f1加括号运行就表示运行了bar函数。
在执行bar函数的过程中,bar函数访问到了外层foo函数中定义的变量,这就是一个典型的闭包函数

那使用闭包函数有什么好处呢??在上面的例子里,f1的值是bar函数的内存地址,f1加括号运行就是在运行bar函数。

又由于f1是一个全局变量,这意味着可以在整个程序的任意位置都可以运行f1函数,此时再定义一个函数,在这个函数内部调用f1函数,

    def foo():print("hello world in foo")name = "python"def bar():print(name)print("hello world in bar")return barf1 = foo()def func():name = "aaaaa"f1()func()

来分析一下程序的执行过程:

1.运行func函数,程序会先在内存中申请一块空间以保存name变量的值,然后运行f1函数,f1是在全局中定义的变量,所以一定可以找到f1函数的内存地址
2.f1加括号运行,就是在执行一个闭包函数,这个闭包函数内部引用了name这个变量
3.name这个变量在bar函数的外部已经定义了,所以在func函数内部调用f1函数,也就是bar函数时,其引用的变量依然是foo函数内部定义的name变量,而不是func函数内部定义的name变量,
4.因为f1函数的内部已经包含了name这个函数的值,所以就算在func函数内部也定义了name这个变量,程序执行的结果打印的依然是foo函数内部定义的name的值

程序执行结果

hello world in foo
python
hello world in bar

怎样验证一个函数是闭包函数

首先,闭包函数都有一个特有的属性:closure

在上面的例子里,打印f1的__closure__属性

    def foo():name = "python"def bar():print(name)print("hello world in bar")return barf1 = foo()print(f1.__closure__)

打印结果如下:

(<cell at 0x0000000001DF5708: str object at 0x0000000001E79688>,)

可以看到__closure__属性的打印结果是一个元组形式的,其值就是f1函数的外层函数作用域

此时可以调用__closure__返回的元组的元素的cell_contents方法打印出name变量的值

    def foo():name = "python"def bar():print(name)print("hello world in bar")return barf1 = foo()print(f1.__closure__[0].cell_contents)

打印结果如下:

python

可以看到程序已经打印出name变量的值了

即然__closure__的返回结果是一个元组,那么这个元组中一定是可以包含多个值的,看下面的例子

在foo函数内部定义多个变量,然后在bar函数内部打印几个变量的值,

然后运行这个闭包函数,打印闭包函数的__closure__方法

    def foo():print("hello world in foo")name1 = "python1"name2 = "python2"name3 = "python3"name4 = "python4"def bar():print(name1)print(name2)print(name3)print(name4)print("hello world in bar")return barf1 = foo()print(f1.__closure__)

程序执行结果

(<cell at 0x0000000002145708: str object at 0x00000000021C9260>,
<cell at 0x0000000002145A08: str object at 0x00000000021C93B0>,
<cell at 0x0000000002145768: str object at 0x000000000295BE30>,
<cell at 0x0000000002145C18: str object at 0x0000000002963880>)

由于在foo函数内部定义了4个变量,而且在bar函数内部引用了这4个变量,所以打印这个闭包函数的__closure__方法,返回的元组中就有4个元素

现在可以分别打印返回的元组中的这4个字符串对象的值了

    def foo():name1 = "python1"name2 = "python2"name3 = "python3"name4 = "python4"def bar():print(name1)print(name2)print(name3)print(name4)print("hello world in bar")return barf1 = foo()print(f1.__closure__[0].cell_contents)print(f1.__closure__[1].cell_contents)print(f1.__closure__[2].cell_contents)print(f1.__closure__[3].cell_contents)

程序执行结果

python1
python2
python3
python4

那么现在还剩下最后一个问题了,那就是闭包函数的内层函数一定要返回吗??

来看下面一个例子

    def foo():name = "python1"def bar():print(name)print(bar.__closure__)foo()

定义了一个嵌套函数,然后这个嵌套函数的内层函数没有被返回,而是直接打印内层函数的__closure__方法,然后直接调用外层函数。

程序执行结果

(<cell at 0x0000000002155708: str object at 0x00000000021D9688>,)

依然打印出了内层函数的引用的变量对象

这说明闭包函数的内层函数还一定要返回

闭包函数的内层函数可以调用全局变量吗??

把外层函数内部定义的变量改为全局变量,然后在内层函数中引用这个变量

    name = "python1"def foo():def bar():print(name)print(bar.__closure__)f=foo()print(f)

程序执行结果

None
None

可以看到,程序的执行结果是两个None,嵌套函数的内层函数的__closure__函数的值为None

这说明foo函数的内层嵌套函数bar调用的全局变量没有成功,所以上面的例子不是一个闭包函数

关于闭包函数的一些总结:

闭包的定义为:在函数内部定义的函数,称为内部函数内部函数调用了外部函数的局部变量即使内部函数返回了,还是可以使用局部变量通常闭包函数的内层函数都要被返回给外部函数闭包函数的外部函数可以在任何地方被调用,而不再受函数定义时层级的限制

闭包函数的作用

1.闭包函数自带函数作用域

正常意义上的函数,在函数执行过程中查找变量的顺序是一层一层向外找,符合LEGB(Local->Enclose->Global->Built in)法则的,

但是对闭包函数来说,查找变量只会找内部函数外面的那一层,因为闭包函数本身就自带一层作用域,这样才符合"闭包"两个字的意思

2.延迟计算(也叫惰性计算)

看下面的例子

    def func():name="python"def bar():print(name)return barf=func()print(f.__closure)

在上面的例子里,执行func()函数的返回结果是一个包含自带的某种状态的函数,实际上这个函数并没有执行,

以后想执行这个自带状态的函数时,把func()返回结果所赋值的那个变量加括号就可以执行了,

3.要想让一个函数始终保持一种状态,就可以使用闭包

例子:

    name="python"def func():print("I like %s" % name)func()

上面的代码执行结果会打印一行:"I like python"

但是我们知道,在不同的地方调用func函数,打印的结果很大可能是不一样的

那么如果我想不管在什么地方调用func函数,打印的结果都是"I like python"时,

就可以使用闭包了。

    def func1():name="python"def func():print("I like %s" % name)return funcfunc=func1()func()

如上图所示,在func函数外面再包含一层函数func1,执行func1函数,再把func1函数的返回结果赋值给func这个变量

此时func就是一个闭包函数了,把func函数加括号就可以执行了

而且我们一定知道,此时func函数的执行结果一定会打印"I like python"这句话,而且不管func函数在程序的哪个位置被调用,执行结果都是一样的。

python中的闭包函数相关推荐

  1. python中的闭包函数与自由变量

    什么是闭包? 简单说,闭包就是根据不同的配置信息得到不同的结果 再来看看专业的解释:闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数.这个被引用的自由变 ...

  2. Python 中的闭包、匿名函数、decorator 装饰器与python的偏函数

    Python中的闭包 def calc_sum(lst):def lazy_sum():return sum(lst)return lazy_sum 像这种内层函数引用了外层函数的变量(参数也算变量) ...

  3. python闭包的应用场景_简单谈谈Python中的闭包

    Python中的闭包 前几天又有人留言,关于其中一个闭包和re.sub的使用不太清楚.我在脚本之家搜索了下,发现没有写过闭包相关的东西,所以决定总结一下,完善Python的内容. 1. 闭包的概念 首 ...

  4. python中的高等函数初探

    python中的高等函数初探 http://blog.csdn.net/ai_s_ye/article/details/44685305 高阶函数,即是能够把函数作为参数的函数了 我在这里只是体到部分 ...

  5. 什么是闭包及Python中的闭包

    什么是闭包 Objects are data with methods attached. Closures are functions with data attached. 一般来说,我们都非常熟 ...

  6. python中的闭包(closure)

    背景 本文尝试介绍Python中的闭包(closure),包括闭包是什么? 为什么要使用闭包?如何使用闭包? 嵌套函数及非局部变量 在介绍闭包之前,需要先明白什么是嵌套函数和非局部变量.在一个函数(f ...

  7. Python中的闭包

    (如转载,请注明出处,谢谢.) 闭包这个概念在很多语言中都有涉及,本文主要谈谈python中的闭包.Python中使用闭包主要是在进行函数式开发时使用. 一,定义 python中的闭包从表现形式上定义 ...

  8. Python 中的闭包介绍

    引言 闭包是优雅的 Python 结构.在本文中,我们将了解它们,如何定义闭包,为什么以及何时使用它们. 但是在讨论什么是闭包之前,我们必须首先理解什么是嵌套函数,以及作用域规则是如何为它们工作的.那 ...

  9. python中的pop()函数和popleft()函数

    python中的pop()函数和popleft()函数 首先对于pop而言,它是用于stack中的: stack = [1, 2, 3, 4] print(stack) stack.append(6) ...

最新文章

  1. 【分享】博士生提高科研幸福感的途径
  2. php常用的数组函数及功能,PHP 常用数组函数 (1)
  3. 安装windows2003+SQL Server2005集群
  4. mysql5.7主从复制遇到的坑
  5. windows修改右键菜单显示内容(非所有菜单适用)
  6. 推荐一个vs自带工具分析代码的复杂度
  7. win7下手动配置apache+ php + mysql 记
  8. .fit文件读取--head信息--修改head--读取csv文件-------ska暑期训练
  9. 如何使用计算机模拟,手把手教你电脑手机模拟器MuMu模拟器怎么使用
  10. RUP软件开发生命周期
  11. 基于感知器准则的线性分类器设计
  12. trainNetwork - Matlab官网介绍的中文版
  13. 超详细TMS-EEG数据处理教程(下)
  14. c++11伪随机数生成库:random
  15. matlab 获取文件毫秒时间,在Matlab中经过的时间,以毫秒为单位,具有不同的日期...
  16. [ML-03] Matplotlib-3
  17. python快手爬虫:解决粉丝数、 关注数等字体加密
  18. 3D-HEVC解码器一
  19. 西门子1200PLC控制加KPT1200触摸屏,污水处理厂自控项目实例
  20. oracle教程目录(我要自学网)

热门文章

  1. Android手机中“本地号码”显示为“未知”的解决方法
  2. 如何在SATA驱动装WinPE
  3. 详解RGB和YUV色彩空间转换
  4. java屠龙_Java中的屠龙之术——如何修改语法树
  5. MATLAB算法实战应用案例精讲-【数模应用】主效应交互效应单独效应
  6. React-Native仿某电商商品详情页面
  7. Adobe Flash Professional CS5 下载
  8. Halcon实例分析——autobahn.hdev快速检测道路标志
  9. Auto CAD二次开发:基于VBA语言的画圆软件开发
  10. 华为笔记本电脑计算机在哪里打开,华为笔记本找不到启动设备