python推导式特殊用法

字典推导式

>>> dic = {x: x**2 for x in (2, 4, 6)}
>>> dic
{2: 4, 4: 16, 6: 36}
>>> type(dic)
<class 'dict'>

集合推导式

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'d', 'r'}
>>> type(a)
<class 'set'>

元组推导式

圆括号在Python中被用作生成器的语法了,没有元组推导式。要通过类似方法生成元组,需要显式调用元组的类型转换函数tuple(),如下所示:

tup = tuple(x for x in range(9))
print(tup)
print(type(tup))

------------------------
结果:
(0, 1, 2, 3, 4, 5, 6, 7, 8)
<class 'tuple'>

面试真题

result = [lambda x: x + i for i in range(10)]
print(result[0](10))

这是一个结合了变量作用域、列表推导式和匿名函数的题目,其实答案是19,并且result0~9的结果都是19。

这是因为函数具有调用时才查找变量的特性。在你没调用它之前,它不会保存也不关心它内部变量的具体值。只有等到你调用它的时候,它才逐一去找这些变量的具体值。这里的result[0]被调用的时候,变量i已经循环完毕,变成9了,而不是想象中的动态0-9值。

使用debug查看的话,最后显示的是 x=10,i=9 最终结果是19

分析:
在列表生成式内定义的lambda函数是一个闭包,而变量i属于这个闭包引用的外部列表生成式中的变量。因此,在lambda函数内的i并不会被立即求值,而是会被保留为引用,直到调用这个lambda函数时,才去获取i的值。在列表生成式结束后,因为range(10)的关系i的当前值为9,也就是说生成的列表中每个lambda函数都是lambda x: x + 9,而不是一般所想象的lambda x: x+0, lambda x: x+1, ..., lambda x: x+9。因此,将10作为参数传递进无论哪个lambda函数,得到的结果都是10+9=19。

那如果不想要这样的结果,想要i是循环的值怎么办?不要直接引用上层变量,把变量直接传进来。这样一来结果是10

result = [lambda x, i=i: x + i for i in range(10)]
print(result[0](10))
posted @ 2020-08-11 10:50  哈喽哈喽111111  阅读(186)  评论(0编辑  收藏  举报