一道神奇的Python面试题,你会吗?

发表于:2019-3-14 10:05

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:上海小胖    来源:思否

  无意间,看到这么一道Python面试题:以下代码将输出什么?
   def testFun():
  temp = [lambda x : i*x for i in range(4)]
  return temp
  for everyLambda in testFun():
  print (everyLambda(2))
  脑中默默一想,这还用说么,肯定是:
   0
  2
  4
  6
  最后一看答案,竟然是:
    6
  6
  6
  6
  于是带着怀疑的心态(其实是不服输,不认错),打开编辑器,快速一敲,果然是:
  
  怀疑了人生半天,本来还想黑,WTF Python…然后才想通是自己太生疏......
  最后发现原因竟是:Python 的闭包的后期绑定导致的 late binding。
  这意味着在闭包中的变量是在内部函数被调用的时候被查找,所以当任何 testFun() 返回的函数被调用,i 的值是在它被调用时的周围作用域中查找。
  也就是说无论哪个返回的函数被调用,for 循环都已经完成了,i 最后的值是 3,因此,每个返回的函数 testFun 的值都是 3。
  因此一个等于 2 的值被传递进以上代码,它们将返回一个值 6 (比如: 3 x 2)。
  究竟如何才能实现出这样的结果呢?
    0
  2
  4
  6
  想了想,若能立即绑定参数,或者直接不用闭包总该行吧,用另一种方式避免 i 的改写。
  回忆了之前所学知识,最后酝酿出了四种解决方案。
  第一种:创建一个闭包,通过使用默认参数立即绑定它的参数
   def testFun():
  temp = [lambda x, i=i: i * x for i in range(4)]
  return temp
  for everyLambda in testFun():
  print(everyLambda(2))
  第二种:使用functools.partial 函数,把函数的某些参数(不管有没有默认值)给固定住(也就是相当于设置默认值)
   from functools import partial
  from operator import mul
  def 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 * x
  for everyLambda in testFun():
  print(everyLambda(2))
  最终运行结果:
 
  有了解决方案后,又陷入了怀疑自己,这个题目究竟是考察的是什么?是在考面试者闭包相关知识以及Python 的闭包的后期绑定问题么?
  若将题目改成:以下代码输出的结果是(0,2,4,6)么?如果不是,你将会怎么做,让它变成(0,2,4,6)?这样会不会更有意思点呢?欢迎大家出妙招,看究竟有多少招?(哈哈哈!!!)

       上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号