博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一道神奇的Python面试题,你会吗?
阅读量:6072 次
发布时间:2019-06-20

本文共 1564 字,大约阅读时间需要 5 分钟。

关注公众号:「Python专栏」,后台回复「爬虫书籍」,即可获得2本Python爬虫相关的电子书

无意间,看到这么一道Python面试题:以下代码将输出什么?

def testFun():    temp = [lambda x : i*x for i in range(4)]    return tempfor everyLambda in testFun():    print (everyLambda(2))复制代码

脑中默默一想,这还用说么,肯定是:

0246复制代码

最后一看答案,竟然是:

6666复制代码

于是带着怀疑的心态(其实是不服输,不认错),打开编辑器,快速一敲,果然是:

怀疑了人生半天,本来还想黑,WTF Python…然后才想通是自己太生疏......

最后发现原因竟是:Python 的闭包的后期绑定导致的 late binding。

这意味着在闭包中的变量是在内部函数被调用的时候被查找,所以当任何 testFun() 返回的函数被调用,i 的值是在它被调用时的周围作用域中查找。

也就是说无论哪个返回的函数被调用,for 循环都已经完成了,i 最后的值是 3,因此,每个返回的函数 testFun 的值都是 3。

因此一个等于 2 的值被传递进以上代码,它们将返回一个值 6 (比如: 3 x 2)。

究竟如何才能实现出这样的结果呢?

0246复制代码

想了想,若能立即绑定参数,或者直接不用闭包总该行吧,用另一种方式避免 i 的改写。

回忆了之前所学知识,最后酝酿出了四种解决方案。

第一种:创建一个闭包,通过使用默认参数立即绑定它的参数

def testFun():    temp = [lambda x, i=i: i * x for i in range(4)]    return tempfor everyLambda in testFun():    print(everyLambda(2))复制代码

第二种:使用functools.partial 函数,把函数的某些参数(不管有没有默认值)给固定住(也就是相当于设置默认值)

from functools import partialfrom operator import muldef testFun():    return [partial(mul, i) for i in range(4)]for everyLambda in testFun():    print(everyLambda(2))复制代码

第三种:优雅的写法,直接用生成器

def testFun():    return (lambda x, i=i: i * x for i in range(4))for everyLambda in testFun():    print(everyLambda(2))复制代码

第四种:利用yield的惰性求值的思想

def testFun():    for i in range(4):        yield lambda x: i * xfor everyLambda in testFun():    print(everyLambda(2))复制代码

最终运行结果:

有了解决方案后,又陷入了怀疑自己,这个题目究竟是考察的是什么?是在考面试者闭包相关知识以及Python 的闭包的后期绑定问题么?

若将题目改成:以下代码输出的结果是(0,2,4,6)么?如果不是,你将会怎么做,让它变成(0,2,4,6)?这样会不会更有意思点呢?欢迎大家出妙招,看究竟有多少招?(哈哈哈!!!)

转载于:https://juejin.im/post/5c8839e351882528e800ef2c

你可能感兴趣的文章
根据Uri获取文件的绝对路径
查看>>
Flutter 插件开发:以微信SDK为例
查看>>
.NET[C#]中NullReferenceException(未将对象引用到实例)是什么问题?如何修复处理?...
查看>>
边缘控制平面Ambassador全解读
查看>>
Windows Phone 7 利用计时器DispatcherTimer创建时钟
查看>>
程序员最喜爱的12个Android应用开发框架二(转)
查看>>
vim学习与理解
查看>>
DIRECTSHOW在VS2005中PVOID64问题和配置问题
查看>>
MapReduce的模式,算法以及用例
查看>>
《Advanced Linux Programming》读书笔记(1)
查看>>
zabbix agent item
查看>>
一步一步学习SignalR进行实时通信_7_非代理
查看>>
AOL重组为两大业务部门 全球裁员500人
查看>>
字符设备与块设备的区别
查看>>
为什么我弃用GNOME转向KDE(2)
查看>>
Redis学习记录初篇
查看>>
爬虫案例若干-爬取CSDN博文,糗事百科段子以及淘宝的图片
查看>>
Web实时通信技术
查看>>
第三章 计算机及服务器硬件组成结合企业运维场景 总结
查看>>
IntelliJ IDEA解决Tomcal启动报错
查看>>