浅析Python闭包
1、什么是闭包
在介绍闭包概念前,我们先来看一段简短的代码
def sum_calc(*args):
def wrapper():
sum = 0
for n in args:
sum += n;
return sum
return wrapper
很显然,这段代码定义了一个名为sum_calc的函数,但和定义的普通函数不同的是这个函数体的内部又定义了一个名为wrapper的函数,并且sum_calc函数的返回值是内部定义wrapper函数。
现在我们开始来调用sum_calc函数,看看会出现哪些有趣的事情
>>> f = sum_calc(1, 2, 3, 4, 5)
>>> f
<function sum_calc.<locals>.wrapper at 0x0000025693AC2D30>
>>> f()
15
从运行结果来看,当我们调用sum_calc时,返回的并不是求和结果,而是内部定义的求和函数。
继续调用sum_calc返回函数时,才真正计算出求和的结果。
当我们继续调用一次sum_calc,传入相同参数
>>> f1 = sum_calc(1, 2, 3, 4, 5)
>>> f2 = sum_calc(1, 2, 3, 4, 5)
>>> f1 == f2
False
>>> f1()
15
>>> f2()
15
每次调用sum_calc,即使传入相同的参数,两次返回的对象不同,且f1()和f2()的结果互不影响。
在这个例子中,我们在sum_calc函数中定义的wrapper函数,wrapper函数可以引用外部函数sum_calc的参数和局部变量,当sum_calc返回函数wrapper时,相关参数保存在返回的函数中,可以被返回的函数继续使用,我们把这种情况称为“闭包”。
参考维基百科,对“闭包”进行更严谨的解释:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
2、闭包陷阱
def my_fun():
fs = []
for i in range(0, 3):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都放在列表中返回。
我们可能认为,f1()、f2()、f3()结果是0、1、4,但实际结果是4
>>> f1()
4
>>> f2()
4
>>> f3()
4
这个例子可以说是典型的错误使用闭包的案例,my_fun返回的并不是一个闭包函数,而是一个包含三个闭包函数的一个列表。
在返回闭包列表fs之前for循环的变量的值已经发生改变了,循环内闭包函数仅声明了自己计算方式,并不会立即使用当前i的值进行计算。只有在真正调用闭包函数时,才会真正的执行闭包函数内的计算,而此时存放的i的值已经是2,所以f1()、f2()、f3()的结果是4而不是我在之前期待的0、1、4。
经过上面的分析,我们得出下面一个重要的经验:返回闭包中不要引用任何循环变量,或者后续会发生变化的变量。
正确写法
def my_fun(*args):
L = []
for i in range(3):
def wrapper(_i = i):
return _i * _i
L.append(wrapper)
return L
3、闭包实现机制
闭包比普通的函数多了一个 __closure__ 属性,该属性记录着自由变量内容。当闭包被调用时,系统就会根据该地址找到对应的自由变量,完成整体的函数调用
还以 sum_calc() 为例,当其被调用时,可以通过 __closure__ 属性获取自由变量(也就是程序中的 args参数)内容,例如:
def sum_calc(*args):
def wrapper():
sum = 0
for n in args:
sum += n;
return sum
return wrapper
输出结果:
>>> f1 = sum_calc(1, 2, 3, 4, 5)
>>> f1.__closure__
(<cell at 0x0000025693A5E4C0: tuple object at 0x0000025693AE5400>,)
>>> f1.__closure__[0].cell_contents
(1, 2, 3, 4, 5)
可以看到,显示的内容是一个tuple类型,这就是f1中自由变量args的值。还可以看到,__closure__ 属性的类型是一个元组,这表明闭包可以支持多个自由变量的形式。
浅析Python闭包的更多相关文章
- 浅析Python装饰器
1.什么是装饰器 在介绍装饰器之前,我们先来思考一个问题:使用Python语言进行程序设计时,如果我们想扩展一个函数的功能,一般会怎么做呢? 比如,有一个名为print_info函数,当前该函数内只做 ...
- Python 闭包
什么是闭包? 闭包(closure)是词法闭包(lexical closure)的简称.闭包不是新奇的概念,而是早在高级程序语言开始发展的年代就已产生. 对闭包的理解大致分为两类,将闭包视为函数或者是 ...
- Python闭包与函数对象
1. Python闭包是什么 在python中有函数闭包的概念,这个概念是什么意思呢,查看Wikipedia的说明如下: “ In programming languages, closures (a ...
- Python闭包及装饰器
Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...
- Python闭包详解
Python闭包详解 1 快速预览 以下是一段简单的闭包代码示例: def foo(): m=3 n=5 def bar(): a=4 return m+n+a return bar >> ...
- Python闭包及其作用域
Python闭包及其作用域 关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记 如果在一个内部函数里,对一个外部作用域(但不是全局作用域 ...
- Python 闭包小记
闭包就是能够读取其他函数内部变量的函数.例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“.在本质上,闭包是将函数内部和函数外部连接起来 ...
- 理解Python闭包概念
闭包并不只是一个python中的概念,在函数式编程语言中应用较为广泛.理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想. 1.概念介绍 首先看一下维基上对闭 ...
- Python闭包举例
Python闭包的条件: 1.函数嵌套.在外部函数内,定义内部函数. 2.参数传递.外部函数的局部变量,作为内部函数参数. 3.返回函数.外部函数的返回值,为内部函数. 举例如下: def line_ ...
随机推荐
- 【模板】【P3402】可持久化并查集
(题面来自洛谷) 题目描述 n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 ...
- 蓝桥杯——Java集合练习题
回文数.维密.约瑟夫环 回文数 问题描述: 123321是一个非常特殊的数,它从左边读和从右边读是一样的.输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n. 输入格式: ...
- 面试官问Linux下如何编译C程序,如何回答?为你编译演示
文章来源:嵌入式大杂烩 作者:ZhengNL Windows下常用IDE来编译,Linux下直接使用gcc来编译,编译过程是Linux嵌入式编程的基础,也是嵌入式高频基础面试问题. 一.命令行编译及各 ...
- java抽象类,多态1
1 package pet_2; 2 3 public abstract class Pet { 4 private String name; 5 6 public String getName() ...
- AndroidStudio中默认不导入org.apache.http等包的解决方法
参考:http://www.cnblogs.com/xiadongqing/p/5942459.html Eclipse ADT中默认引入了org.apache.http包,而AndroidStudi ...
- 基于spring@aspect注解的aop实现
第一步:编写切面类 package com.dascom.hawk.app.web.tool; import org.aspectj.lang.JoinPoint; import org.aspect ...
- 第11.16节 Python正则元字符“()”(小括号)与组(group)匹配模式
一. 什么是组 关于组匹配模式,Python官网上说得比较简单,也没有这个名词,只有组这个名词,老猿查了比较多的资料和做了相关测试之后才理解. 组匹配模式,就是在匹配的正则表达式中使用小括号" ...
- PyQt(Python+Qt)学习随笔:Qt Designer中部件mimimumSize和maximumSize的含义
1.mimimumSize mimimumSize表示部件能被缩小到的最小尺寸,单位为像素,缩小到该尺寸后不能再进一步缩小了.如果部件在布局管理器中,且布局管理器也设置了最小尺寸,则部件本身的最小尺寸 ...
- sql bool盲注
[CISCN2019 总决赛 Day2 Web1]Easyweb 考察: robots.txt image.php?bak文件泄露,image.php.bak可以下载别的不大行 盲注 php日志挂马 ...
- Hive数据导入HBase引起数据膨胀引发的思考
最近朋友公司在做一些数据的迁移,主要是将一些Hive处理之后的热数据导入到HBase中,但是遇到了一个很奇怪的问题:同样的数据到了HBase中,所占空间竟增长了好几倍!详谈中,笔者建议朋友至少从几点原 ...