今天的文章萌生于一个python试题:
参考了网上的讲解都不甚清晰,咱们今天用白话文来解释一波
list1 = [lambda x: x + i for i in range(10)]
for list2 in list1:
print(list2(5))
执行结果:
14
14
14
14
14
14
14
14
14
14
并不是我们预期的结果,那么这个时候我的头脑里就出现了一个首歌:小朋友,你是否有很多问号?
按照我们的推测,不应该是5,6,7,8,9,10,11,12,13,14这样的答案吗?
那么这个题看似简单,其实内部由很多的代码结构组成。这个时候就需要我们去拆分这个语句了。
我们都知道,lambda函数可以写成:
def fun1(x):
return x + i
那么,我们的列表推导式拆开来写是怎么做到的呢,其实也是定义一个函数来完成列表数据的添加。
lst = []
def fun():
for i in range(10):
lst.append(i)
return lst
那么这个完整的语句改写是怎么写的呢?
lst = []
def fun():
for i in range(10):
def fun1(x):
return x + i
lst.append(fun1)
return lst
r = fun()
print(r)
执行结果:
[<function fun.<locals>.fun1 at 0x0000014FA44BEF28>, <function fun.<locals>.fun1 at 0x0000014FA44C30D0>, <function fun.<locals>.fun1 at 0x0000014FA44C31E0>, <function fun.<locals>.fun1 at 0x0000014FA44C3268>, <function fun.<locals>.fun1 at 0x0000014FA44C32F0>, <function fun.<locals>.fun1 at 0x0000014FA44C3378>, <function fun.<locals>.fun1 at 0x0000014FA44C3400>, <function fun.<locals>.fun1 at 0x0000014FA44C3488>, <function fun.<locals>.fun1 at 0x0000014FA44C3510>, <function fun.<locals>.fun1 at 0x0000014FA44C3598>]
大家对于这个结构是不是有那么一丢丢的熟悉呢?
没错,他就是一个闭包函数,返回出来的结果就是一个列表里面存放的fun1的函数对象。那么问题来了,既然是一个函数对象,我们调用函数再给它传递参数,不应该就是我们的预期结果吗?为什么全部都是14的结果呢?
这里就涉及到了python的闭包函数的特性了:内部函数不经过特殊的方式没有办法修改外部函数的变量。
我们这里使用的是外部函数的变量i,那么当我们的for循环执行完十次的时候,我们列表中生成的每一个函数对象都是使用了变量i的,而且都是指向的外部函数中变量i的内存地址,那么当最后一次循环执行完毕的时候,我们的i是不是变成了9,所以,每一个函数对象中的变量i的值都变为了9,至此,当我们去做for循环遍历这个列表并传递x=5的值时,就都变为了5+9=14的结果。
其他的lambda函数结合列表推导式都是同样的逻辑,你学废了吗?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。