闭包(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. Windows 7 无密码文件共享

    Windows7中创建无密码的文件共享的几个步骤: 在“控制面板\所有控制面板项\网络和共享中心\高级共享设置”开启“关闭密码保护共享”和“启用文件和打印机共享”.关闭密码保护共享的操作会启用Gues ...

  2. 浅谈iPhone OS(iOS)架构

    iPhone OS(现在叫iOS)是iPhone, iPod touch 和 iPad 设备的操作系统

  3. 使用librtmp进行H264与AAC直播

    libx264 版本是 128libfaac 版本是 1.28 1.帧的划分 1.1 H.264 帧 对于 H.264 而言每帧的界定符为 00 00 00 01 或者 00 00 01. 比如下面的 ...

  4. Sharepoint文档的CAML分页及相关筛选记录

    写这篇文章的初衷是因为其他的业务系统要调用sharepoint的文档库信息,使其他的系统也可以获取sharepoint文档库的信息列表.在这个过程中尝试过用linq to sharepoint来获取文 ...

  5. Git 学习笔记--Git下的冲突解决

    冲突的产生 很多命令都可能出现冲突,但从根本上来讲,都是merge 和 patch(应用补丁)时产生冲突. 而rebase就是重新设置基准,然后应用补丁的过程,所以也会冲突. git pull会自动m ...

  6. AddParent

    using UnityEngine; using UnityEditor; using System.Collections; public class AddParent : ScriptableO ...

  7. Android开发懒人库 -- ButterKnife (转载)

    ButterKnife:8.1.0的使用   http://www.jianshu.com/p/0392199a682b http://www.cnblogs.com/flyme/p/4517560. ...

  8. AndroidのTextView之CompoundDrawable那些坑

    TextView有几个属性android:drawableXXX,通常是在环绕文字周边显示一个图像,但是这有个坑就是文字和图片可能会对不齐. 纵使你设置gravity还是layout_gravity= ...

  9. 怎么修改mysql主键(id)的值为自增

    alter table tb_name modify id int auto_increment primary key

  10. java框架---->quartz的使用(一)

    Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.今天我们就来学习一下它的使用,这里会分篇章对它进行介绍.只是希望能有个人,在我说没事的时候,知道我不 ...