一、什么是闭包?

如果一个内嵌函数访问外部嵌套函数作用域的变量,并返回这个函数,则这个函数就是闭包

闭包必须满足三个条件:

1. 必须有一个内嵌函数
    2. 内嵌函数必须引用外部嵌套函数中的变量
    3. 外部函数返回值必须是内嵌函数

闭包的特点:

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

很晦涩很难理解啊~我们来看一段代码^.^

#闭包函数的实例
2 # outer是外部函数 a和b都是外函数的临时变量
3 def outer( a ):
4 b = 10
5 # inner是内函数
6 def inner():
7 #在内函数中 用到了外函数的临时变量
8 print(a+b)
9 # 外函数的返回值是内函数的引用
10 return inner
11
12 if __name__ == '__main__':
13 # 在这里我们调用外函数传入参数5
14 #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo
15 # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
16 demo = outer(5)
17 # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量
18 # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数
19 demo() #
20
21 demo2 = outer(7)
22 demo2()#
复制代码

从上面例子是一个最简单的很典型的闭包。可能很多名词都不明白是什么意思,没关系,我们把这些名词去解释一下~

1 外函数返回了内函数的引用:

  引用是什么?在python中一切都是对象,包括整型数据1,函数,其实是对象。

  当我们进行a=1的时候,实际上在内存当中有一个地方存了值1,然后用a这个变量名存了1所在内存位置的引用,大家可以把引用理解成地址。a只不过是一个变量名字,a里面存的是1这个数值所在的地址,就是a里面存了数值1的引用。

  相同的道理,当我们在python中定义一个函数def demo():  的时候,内存当中会开辟一些空间,存下这个函数的代码、内部的局部变量等等。这个demo只不过是一个变量名字,它里面存了这个函数所在位置的引用而已。我们还可以进行x = demo, y = demo, 这样的操作就相当于,把demo里存的东西赋值给x和y,这样x 和y 都指向了demo函数所在的引用,在这之后我们可以用x() 或者 y() 来调用我们自己创建的demo() ,调用的实际上根本就是一个函数,x、y和demo三个变量名存了同一个函数的引用。

  有了上面的解释,我们可以继续说,返回内函数的引用是怎么回事了。对于闭包,在外函数outer中 最后return inner,我们在调用外函数 demo = outer() 的时候,outer返回了inner,inner是一个函数的引用,这个引用被存入了demo中。所以接下来我们再进行demo() 的时候,相当于运行了inner函数。

  所以,一个函数,如果函数名后紧跟一对括号,相当于现在我就要调用这个函数,如果不跟括号,相当于只是一个函数的名字,里面存了函数所在位置的引用。

2 外函数把临时变量绑定给内函数:

  按照我们正常的认知,一个函数结束的时候,会把自己的临时变量都释放还给内存,之后变量都不存在了。一般情况下,确实是这样的。但是闭包是一个特别的情况。外部函数发现,自己的临时变量会在将来的内部函数中用到,自己在结束的时候,返回内函数的同时,会把外函数的临时变量送给内函数绑定在一起。所以外函数已经结束了,调用内函数的时候仍然能够使用外函数的临时变量。

  在我编写的实例中,我两次调用外部函数outer,分别传入的值是5和7。内部函数只定义了一次,我们发现调用的时候,内部函数是能识别外函数的临时变量是不一样的。python中一切都是对象,虽然函数我们只定义了一次,但是外函数在运行的时候,实际上是按照里面代码执行的,外函数里创建了一个函数,我们每次调用外函数,它都创建一个内函数,虽然代码一样,但是却创建了不同的对象,并且把每次传入的临时变量数值绑定给内函数,再把内函数引用返回。虽然内函数代码是一样的,但其实,我们每次调用外函数,都返回不同的实例对象的引用,他们的功能是一样的,但是它们实际上不是同一个函数对象。

3 闭包中内函数修改外函数局部变量:

  在闭包内函数中,我们可以随意使用外函数绑定来的临时变量,但是如果我们想修改外函数临时变量,就要用专门的关键字了!

  详细解决方案请参考上一篇博客!

还有一点需要注意:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量

上代码!

 1 #coding:utf8
2 def outer(x):
3 def inner(y):
4 nonlocal x
5 x+=y
6 return x
7 return inner
8
9
10 a = outer(10)
11 print(a(1)) //11
12 print(a(3)) //14

两次分别打印出11和14,由此可见,每次调用inner的时候,使用的闭包变量x实际上是同一个。

二、闭包有啥用?

  很多伙伴很糊涂,闭包有啥用啊?

   装饰器!!详细解析请参考上上篇博客!

python闭包的详细解析的更多相关文章

  1. python lambda函数详细解析(面试经常遇到)

    1 作用:通常是用来在python中创建匿名函数的 2 格式: lambda 参数[,参数] : 表达式 3 注意: (1)lambda定义的是单行函数, 如果需要复杂的函数,应该定义普通函数 (2) ...

  2. 【转】python中的闭包详细解析

    一.什么是闭包? 如果一个内嵌函数访问外部嵌套函数作用域的变量,并返回这个函数,则这个函数就是闭包 闭包必须满足三个条件: 1. 必须有一个内嵌函数    2. 内嵌函数必须引用外部嵌套函数中的变量  ...

  3. Python闭包详解

    Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...

  4. Python闭包及其作用域

    Python闭包及其作用域 关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记 如果在一个内部函数里,对一个外部作用域(但不是全局作用域 ...

  5. Python 闭包小记

    闭包就是能够读取其他函数内部变量的函数.例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“.在本质上,闭包是将函数内部和函数外部连接起来 ...

  6. 理解Python闭包概念

    闭包并不只是一个python中的概念,在函数式编程语言中应用较为广泛.理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想. 1.概念介绍 首先看一下维基上对闭 ...

  7. python 闭包和装饰器

    python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...

  8. Thrift之代码生成器Compiler原理及源码详细解析2

    我的新浪微博:http://weibo.com/freshairbrucewoo. 欢迎大家相互交流,共同提高技术. 2  t_generator类和t_generator_registry类 这个两 ...

  9. Thrift之代码生成器Compiler原理及源码详细解析1

    我的新浪微博:http://weibo.com/freshairbrucewoo. 欢迎大家相互交流,共同提高技术. 又很久没有写博客了,最近忙着研究GlusterFS,本来周末打算写几篇博客的,但是 ...

随机推荐

  1. ADB文件及文件夹操作

    1.创建文件夹: adb shell mkdir /data/local/tmp/local多级的一次只能创建一级adb shell mkdir /data/local/tmp/local/tmp 2 ...

  2. centos 支持安装libsodium

    yum install epel-release -y yum install libsodium -y 然后没了.

  3. vuex状态管理-数据改变不刷新

    困惑: 在页面初始化的时候,我提交到vuex状态管理,然后在获取的时候获取不到,我找到了出错的地点,并进行了修改,然后可以获取到状态 但是不知道原因? 定义了如下的state const state ...

  4. 删除已经提交到远程仓库的gitignore文件

    亲们支持我的新博客哦==>地址(以后更新会尽量在新博客更新,欢迎大家访问加入我的后宫w) ) gitignore里新添加了需要过滤的文件,但是之前已经提交到了远程分支 解决方法: # 1.为避免 ...

  5. 彻底征服 Spring AOP 之 实战篇

      Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个 ...

  6. Python实践练习:强口令检测

    题目: 写一个函数,它使用正则表达式,确保传入的口令字符串是强口令.强口令的定义是:长度不少于 8 个字符,同时包含大写和小写字符,至少有一位数字.你可能需要用多个正则表达式来测试该字符串,以保证它的 ...

  7. web监控,if 语句

    对页面的测试  curl "] #if [`curl -I http://10.0.0.7 &>/dev/null|head -l|grep 200|wc -l` -eq 1] ...

  8. 0初识Linux

    今天三八妇女节,Linux就该这么学,开课第一天.信心满满,激动,期待,要努力了.(博客为预习写的,今天又做了更新.)   Linux第一印象就是黑色背景屏幕,上面还有好多代码,敲的一手好的命令操控着 ...

  9. 转: rem与px的转换

    rem是相对于根元素<html>,这样就意味着,我们只需要在根元素确定一个参考值,这个参考值设置为多少,完全可以根据您自己的需求来定.· 我们知道,浏览器默认的字号16px,来看一些px单 ...

  10. redis安装--单机

    本例基于CentOS7.2系统安装 环境需求: 关闭防护墙,selinux 安装好gcc等编译需要的组件 yum -y install gcc c++ 到redis官网下载合适版本的redis安装包, ...