当前位置: 首页 > 科技观察

一道Python面试题让我明白了殊途同归,但我开始怀疑自己

时间:2023-03-19 15:40:57 科技观察

无意中看到这样一道Python面试题:下面的代码会输出什么?deftestFun():temp=[lambdax:i*xforiinrange(4)]returntempforeveryLambdaintestFun():print(everyLambda(2))在心里默默思考,不用说了,肯定是:0246***看到答案的时候竟然是:6666,于是抱着怀疑的态度(其实我就是不服输,不认错),打开小编,一敲,果然是:怀疑人生好久了,还想hack,WTFPython。。。后来才发现自己太陌生了。。。****发现那个原因是:Python的闭包的后期绑定导致后期绑定,这意味着在调用内部函数时查找闭包中的变量。所以结果是,当testFun()返回的任何一个函数被调用时,那个时候,i的值在它被调用时的周围作用域中查找,并且在那个时候,无论哪个返回函数被调用,for循环已经完成了,i***的值为3,因此,每个返回的函数testFun的值为3。所以在上面的代码中传入一个等于2的值,它们将返回一个值为6(例如:3x2)。我们怎样才能达到这样的结果呢?0246想了想,如果他能马上绑定参数,或者干脆不使用闭包,应该可以,换个方式避免i的重写。回忆之前的学习,***酝酿了四种解决方案:第一种:创建一个闭包,并立即绑定其参数deftestFun():temp=[lambdax,i=i,使用默认参数:i*xforiinrange(4)]returntempforeveryLambdaintestFun():print(everyLambda(2))方法二:使用functools.partial函数固定函数的某些参数(是否有默认值)(即相当于设置默认值)fromfunctoolsimportpartialfromoperatorimportmuldeftestFun():return[partial(mul,i)foriinrange(4)]foreveryLambdaintestFun():print(everyLambda(2))第三种:优雅的写法,直接使用生成器deftestFun():return(lambdax,i=i:i*xforiinrange(4))foreveryLambdaintestFun():print(everyLambda(2))第四种:利用yield惰性求值的思路deftestFun():foriinrange(4):yieldlambdax:i*xforeveryLambdaintestFun():print(everyLambda(2))运行的最终结果:有了解决方案后,我自己陷入了怀疑。这个问题是关于什么的?就是考考面试官的闭包知识,闭包Pythonlatebinding有没有问题?如果把标题改成:下面代码的输出是(0,2,4,6)吗?如果不是,你将如何使它变成(0,2,4,6)?这不是更有趣吗?欢迎大家想出妙招,来看看有多少招?(哈哈哈!!!)