面试题-python 什么是闭包(closure)?
前言
前面学了装饰器,那么闭包和装饰器有什么区别呢?
闭包传递的是变量,而装饰器传递的是函数对象,只是传的参数内容不一样,闭包的概念包含了装饰器,可以说装饰器是闭包的一种,它只是传递函数对象的闭包。
先看一个面试题
先看一个经典的面试题,很有代表性, 运行以下代码会输出什么呢?为什么会是这种结果?
def fun():
temp = [lambda x: i*x for i in range(4)]
return temp
for everyLambda in fun():
print(everyLambda(2))
运行结果
6
6
6
6
运行的结果是4个6 ,并不是我们想的 :0, 2, 4, 6。上面的代码用到了列表推导式,还有个匿名函数lambda,直接去阅读不太好理解,可以把匿名函数转成自己定义一个函数.
于是上面的代码等价于:
"""
def fun():
temp = [lambda x: i*x for i in range(4)]
return temp
for everyLambda in fun():
print(everyLambda(2))
"""
def fun():
temp = []
for i in range(4):
def inner(x):
return i*x
temp.append(inner)
return temp
for everyLambda in fun():
print(everyLambda(2))
为了更好的理解,可以先去掉外面的一层fun()
temp = []
for i in range(4):
def inner(x):
return i*x
temp.append(inner)
for everyLambda in temp:
print(everyLambda(2))
这里只定义了一个函数 inner(), 有 2 个变量,i 是函数外部的变量,x 是函数内部的变量。
现在问题的关键在理解函数外部变量和函数内部变量的区别了, 接下来再看一个简单的例子
a = 1
def myfunc(b):
return a+b
print(myfunc(100))
a = 2
a = 3
print(myfunc(100))
print(myfunc(100))
运行结果:101 103 103
也就是函数外部变量a是可变的,后面给a重新赋值了,会替换前面的值。上面的 inner(x) 函数也是一样,外部变量 i 的值是0, 1, 2, 3变化,最后的3 会覆盖前面的值,所以得到的结果都是6
如何解决上面的问题,接下来就是要说的闭包的概念了!
什么是闭包?
闭包就是外部函数中定义了一个内部函数,当外部函数返回内部函数对象(注意是函数对象)时,程序接收了内部函数的定义(此时并未被执行),当再次执行这个返回值时,这个被返回的函数才能被执行。
创建一个闭包必须满足以下几点:
必须有一个内嵌函数
内嵌函数必须引用外部函数中的变量
外部函数的返回值必须是内嵌函数
闭包和装饰器的区别:闭包传递的是变量,而装饰器传递的是函数,除此之外没有任何区别,或者说装饰器是闭包的一种,它只是传递函数的闭包。
以下是闭包的一个标准示例:
def outer(age):
def inner(name):
print("my name is %s. my age is %s." % (name, age))
return inner
demo = outer("18")
demo("yoyo")
# 运行结果:my name is yoyo. my age is 18.
上面的问题,用闭包来解决
# 闭包
def temp(i): # 一个外层函数
def inner(x): # 内层函数
return i*x
return inner
a = []
for i in range(4):
a.append(temp(i))
print(a)
for j in a:
print(j(2))
运行结果
[<function temp.<locals>.inner at 0x000002A8EE929AE8>,
<function temp.<locals>.inner at 0x000002A8EE929B70>,
<function temp.<locals>.inner at 0x000002A8EE929BF8>,
<function temp.<locals>.inner at 0x000002A8EE929C80>]
0
2
4
6
使用列表推导式
# 闭包
def temp(i): # 一个外层函数
def inner(x): # 内层函数
return i*x
return inner
def fun():
temps = [temp(i) for i in range(4)]
return temps
for everyLambda in fun():
print(everyLambda(2))
这样就可以得到我们的预期结果:0 2 4 6
通过上面的案例就可以了解到闭包的作用了,它保存了函数的外部变量,不会随着变量的改变而改变了。
来源:https://mp.weixin.qq.com/s/vCR8ZzYtu3eUP44Z_Vmwzg
面试题-python 什么是闭包(closure)?的更多相关文章
- 说说Python中的闭包 - Closure
转载自https://segmentfault.com/a/1190000007321972 Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西 ...
- Python中的闭包 - Closure
Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西. 闭包的概念 我们尝试从概念上去理解一下闭包. 在一些语言中,在函数中可以(嵌套)定义另一个 ...
- python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)
1.函数对象 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函 ...
- 【Python】闭包Closure
原来这就是闭包啊... 还是上次面试,被问只不知掉js里面的闭包 闭包,没听过啊...什么是闭包 回来查了下,原来这货叫闭包啊...... —————————————————————————————— ...
- Python深入04 闭包
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 闭包(closure)是函数式编程的重要的语法结构.函数式编程是一种编程范式 (而 ...
- 21.python中的闭包和装饰器
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...
- Swift语言精要-闭包(Closure)
闭包(Closure)这个概念如果没学过Swift的人应该也不会陌生. 学过Javascript的朋友应该知道,在Javascript中我们经常会讨论闭包,很多前端工程师的面试题也会问到什么是闭包. ...
- Python 中的闭包与装饰器
闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...
- 【转】python中的闭包
转自:http://www.cnblogs.com/ma6174/archive/2013/04/15/3022548.html python中的闭包 什么是闭包? 简单说,闭包就是根据不同的配置信息 ...
- Python 入门之 闭包
Python 入门之 闭包 1.闭包 (1)在嵌套函数内使用(非本层变量)和非全局变量就是闭包 (2)_ closure _ 判断是不是闭包 def func(): a = 1 def foo(): ...
随机推荐
- 分布式缓存NewLife.Redis
NewLife.Redis 是一个Redis客户端组件,以高性能处理大数据实时计算为目标. Redis协议基础实现位于Redis/RedisClient,FullRedis为扩展实现,主要增加列表结构 ...
- 《最新出炉》系列入门篇-Python+Playwright自动化测试-48-Route类拦截修改请求-上篇
1.简介 在日常工作和学习中,自动化测试的时候:在加载页面时,可能页面出现很多不是很重要或者不是我们所关注的,这个时候我们就可以选择不加载这些内容,以提高页面加载速度,节省资源.例如:可能页面上图片比 ...
- kubernetes自动扩缩容[HPA控制器 horizontal pod autoscaler]
kubernetes自动扩缩容[HPA控制器 horizontal pod autoscaler] #查看当前hpa控制器版本: [root@k8s-master01 ~]# kubectl get ...
- 查看CentOS版本的方法
1.以下命令对于Linux发行版是通用的: root@MyMail ~ # uname Linux root@MyMail ~ # uname -r 2.6.18-164.el5 [root@loca ...
- 鼠标悬浮显示鼠标停留数据的内容 elementui + vue
先看效果图 直接上代码 <el-tabs v-model="activeName" @tab-click="handleClick"> <el ...
- INFINI Labs 产品更新 | Easysearch 新增 kNN 搜索功能、Console 支持 LDAP 认证登录等
INFINI Labs 产品又更新啦~,包括 Easysearch v1.3.0.Gateway v1.16.0.Console v1.4.0.Agent v0.5.1.本次产品更新了许多实用新特性, ...
- 关于cookie的深入了解
1.cookie的诞生 由于HTTP协议是无状态的,服务端的业务必须带用户状态,cookie的诞生最初就是为了存储web中的用户状态以及其他的相关状态,以方便服务器使用.比如是否用户第一次访问网站,用 ...
- Python3 dict和str互转
# Python3 dict和str互转 import ast str_of_dict = "{'key1': 'key1value111', 'key2': 'key2value222'} ...
- SpringBoot的Security和OAuth2的使用
创建项目 先创建一个spring项目. 然后编写pom文件如下,引入spring-boot-starter-security,我这里使用的spring boot是2.4.2,这里使用使用spring- ...
- scrapy爬取知名问答网站
scrapy爬取知名问答网站 分析及数据表设计 itemloader方式提取question spider爬虫逻辑的实现以及answer的提取 保存数据到mysql中