闭包(Closure)

在一个函数内部定义另一个函数,然后内部函数用到外部函数的变量,把内部函数以及用到的外部变量,合称闭包。

首先复习一下

命名空间与作用域

我们可以把命名空间看做一个大型的字典类型(Dict),里面包含了所有变量的名字和值的映射关系。在 Python 中,作用域实际上可以看做是“在当前上下文的位置,获取命名空间变量的规则”。在 Python 代码执行的任意位置,都至少存在三层嵌套的作用域:

  • local            最内层作用域,最早搜索,包含所有局部变量**(Python 默认所有变量声明均为局部变量)**
  • non-local    所有包含当前上下文的外层函数的作用域,由内而外依次搜索,这里包含的是非局部也非全局的变量
  • global         一直向上搜索,直到当前模块的全局变量
  • built-in        最外层,最后搜索的,内置(built-in)变量

在任意执行位置,可以将作用域看成是对下面这样一个命名空间的搜索:


scopes =
{
"local": {"locals": None,
"non-local": {"locals": None,
"global": {"locals": None,
"built-in": ["built-ins"]}}},
}
 

除了默认的局部变量声明方式,Python 还有globalnonlocal两种类型的声明(nonlocal是Python 3.x之后才有,2.7没有),其中 global 指定的变量直接指向(3)当前模块的全局变量,而nonlocal则指向(2)最内层之外,global以内的变量。这里需要强调指向(references and assignments)的原因是,普通的局部变量对最内层局部作用域之外只有**只读(read-only)**的访问权限,比如下面的例子:

>>>x = 100  #该全局变量可被所有函数调用
>>def main():
x += 1
print(x) >>>main()
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
main()
File "<pyshell#49>", line 2, in main
x += 1
UnboundLocalError: local variable 'x' referenced before assignment

这里抛出UnboundLocalError,是因为main()函数内部的作用域对于全局变量x仅有只读权限,想要在main()中对x进行改变,不会影响全局变量,而是会创建一个新的局部变量,显然无法对还未创建的局部变量直接使用x += 1。如果想要获得全局变量的完全引用,则需要global声明:

>>>x = 100
>>>def main():
global x
x += 1
print(x) >>>main()
print(x) # 全局变量已被改变,后面的全局变量x都为101
101

Python闭包

demo:

# 外部函数
def fun():
print('outer')
# 内部函数
def fun_in():
print('inner')
return fun_in # 调用外部函数
fun()
a = fun()
print(a)
# 调用内部函数
a() # 输出结果
outer
<function fun.<locals>.fun_in at
inner

再写个闭包调用时机的小例子

def fun():
print('---1---')
def fun_in():
print('---2---')
print('---3---')
return fun_in # 注意没有小括号 # fun()
# 输出结果
# ---1---
# ---3--- # 调用 fun_in才输出---2---
a = fun()
print('-------')
a() #输出结果
---1---
---3---
-------
---2---

闭包在内存中的状态

在python函数的使用里,当函数调用结束后,函数对应的内存空间被释放,里面所有东西都被清空

但在闭包中例外,因为函数里面还有东西(内部函数)被引用了。因此外部函数的空间就没被释放(涉及到python回收机制的知识:引用计数)

如果再次调用这个函数,就还会重新生成一份新的内存空间

def fun(number):
def fun_in(number_in):
print('number = %d, number_in = %d' % (number, number_in))
return number + number_in
return fun_in a1 = fun(3)
print(a1(8)) # 11 = 3 + 8 a2 = fun(5)
print(a2(8)) # 13 = 5 + 8 print(a1(9)) # 12 = 3 + 9 print(a2(9)) # 14 = 5 + 9

所以,当通过a1去调用内部函数,和通过a2去调用内部函数的时候,实际上是在不同的内存空间上去跑的。

Python:闭包的更多相关文章

  1. Python 闭包

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

  2. Python闭包与函数对象

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

  3. Python闭包及装饰器

    Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...

  4. Python闭包详解

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

  5. Python闭包及其作用域

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

  6. Python 闭包小记

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

  7. 理解Python闭包概念

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

  8. Python闭包举例

    Python闭包的条件: 1.函数嵌套.在外部函数内,定义内部函数. 2.参数传递.外部函数的局部变量,作为内部函数参数. 3.返回函数.外部函数的返回值,为内部函数. 举例如下: def line_ ...

  9. python 闭包和装饰器

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

  10. Python 闭包(Closure)

    Python  闭包 (Closure) 这里介绍一下python 的闭包 基本概念 闭包(closure)是函数式编程的重要的语法结构. 函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函 ...

随机推荐

  1. SpringMVC由浅入深day02_7上传图片

    7 上传图片 7.1 需求 在修改商品页面,添加上传商品图片功能. 7.2 springmvc中对多部件类型解析 在页面form中提交enctype="multipart/form-data ...

  2. 5 -- Hibernate的基本用法 --2 Hibernate入门

    5.2.1 Hibernate 下载和安装 5.2.2 Hibernate 的数据库操作 5.2.3 在Eclipse中使用Hibernate 啦啦啦

  3. 记安装ubuntu server和一些程序

    1. 安装ubuntu server 按照流程走了一遍,一切画面都正常,就是重启后界面只有一个光标闪啊闪,我不知道应该再装一遍还是找老大来解决,想了下,以前电脑就是因为出错才重装的,现在这个情况有可能 ...

  4. luasocket 接收数据

    在游戏客户端使用luasocket作为网络通信的手段, 有一点很蛋疼, 就是它的receive是阻塞的,  那界面就卡死在那里了,  不过有一个函数:settimeout(), 传入参数0, 表示如果 ...

  5. PHP代码审计笔记--代码执行漏洞

    漏洞形成原因:客户端提交的参数,未经任何过滤,传入可以执行代码的函数,造成代码执行漏洞. 常见代码注射函数: 如:eval.preg_replace+/e.assert.call_user_func. ...

  6. 分析JobInProgress中Map/Reduce任务分配

    1.JobTracker能否决定给当前的TaskTracker节点分配一个Job的具体的哪一个任务? 2.什么是map本地任务? 3.nonRunningMapCache的作用是什么? 4.从Task ...

  7. 给TextView加上多彩效果:改变部分字体的大小和颜色

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/18363899 前言 在实际使用中,有时候会遇到特殊需求,比如pm突发奇想,想 ...

  8. 汉字按首字母排序(javascript,php,mysql实现)

    1.javascript实现 var a = ["啊","得啊_123","得啊_0124","波啊","婆& ...

  9. codeforces水题100道 第十八题 Codeforces Round #289 (Div. 2, ACM ICPC Rules) A. Maximum in Table (brute force)

    题目链接:http://www.codeforces.com/problemset/problem/509/A题意:f[i][1]=f[1][i]=1,f[i][j]=f[i-1][j]+f[i][j ...

  10. Andoid数据存储之SQLite数据库

    SQLite是一个嵌入式的并且是一个轻量级的数据库: SQLite数据库支持大部分SQL语法, 允许使用SQL语句操作数据库, 其本质是一个文件, 不需要安装启动: SQLite数据库打开只是打开了一 ...