2

  今天的文章萌生于一个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函数结合列表推导式都是同样的逻辑,你学废了吗?


活在当下
32 声望38 粉丝