调用 strong res 得到 bad 装饰器 print eve
有这么一个小面试题:
看下面代码请回答输出的结果是什么? 为什么?
- result = [lambdax: x + iforiinrange(10)]
- print(result[0](10))
当你看到这篇文章的时候如果不知道这个知识点肯定会拿去直接运行,输出的结果是什么呢?
结果是:19
通过 result[0~9](10) 结果都是 19 就,懵逼了吧~~
想知道这个我们先看几个知识点
顾名思义,列表生成式就是一个用来生成列表的特定语法形式的表达式。
语法格式:
- [expression
- for iterable_var in iterable]
工作过程:
工作过程类似于:
- L = []
- foriinrange(10):
- # 举例expression 表达式 iterable_var * 5 ,最后把这个结果加到列表中L.append(i * 5)
点到为止,我们来看下我们的这个小面试题
- result = [lambdax: x + iforiinrange(10)]
- # 后面的lambada x:x +i 为expression 这是一个普通的lambada表达式那他生成的结果是什么? 一个一个的函数
- # 看下面的例子就舒服多了L = []
- foriinrange(10):
- L.append(lambdax: x +i)
那在我们执行 result[0](10), 其实就是在执行 lambda 10: 10 + i , 但是为什么每个 i 都是 9 呢?
我们在写一个函数的时候,函数内不保存这个变量的值,而是在执行的时候去找这个值在哪里绑定上的。
举个例子来说我们在函数中定引用了一个变量, 可以不需要提前定义我们只要在使用前定义就可以了, 如下面代码
- def func():
- print(foo)
- foo ="hello tim"
- func()
注:这里有个点稍微提醒下, 调用函数时这个函数必须是提前定义好的,这个我们称之为 "前向引用",而函数内部变量可以后期再定义,我们称之为 "后期绑定"
因为这个变量不是在 lambda 内定义的,而是在列表生成式内定义的,我先把列表生成式翻译一下:
- def make_list():
- L =[]
- foriinrange(10):
- def inner(arg):
- returni + arg
- L.append(inner)
- return L
- result = make_list()
- print(result[2](10))
看上面的代码最后返回的都是一个一个的函数,而这个 i 的值是在循环的时候赋值的,那我们知道这个 i 的值不是在,inner(lambda) 函数中定义的,而是引用的上层函数的变量,当我们使用 inner 去调用的时候,这时这个 for 循环已经结束了,i 的值也就变成固定了 9
所以每当我们通过函数 lambda x: x + i 的时候这个 i 永远是 9
那如果说我不想要这样的结果,我想要 i 是循环的值怎么办,不要直接引用上层变量,把变量传进来就可以了
- result = [lambdax, i=i, : x + iforiinrange(10)]
- print(result[1](10))
翻译一下
- def make_list():
- L =[]
- foriinrange(10):
- definner(arg, i=i):
- returni + arg
- L.append(inner)
- return L
- result = make_list()
- print(result[2](10))
简单解释下这个概念,在嵌套函数内,嵌套函数应用上层函数的变量(不是全局变量)称之为闭包,
- def func():
- x = 1def inner():
- print(x)
当我们执行 func 的时候就会生成一个闭包,func 执行完后里面的变量 x 不会被回收,因为嵌套函数 inner 还在使用它,常见的应用场景就是我们的装饰器
Python【知识点】面试小点列表生成式小坑
来源: http://www.bubuko.com/infodetail-2103590.html