列表推断式
result = [lambda x: x + i for i in range(10)]
print(result[0](10))
乍一看这代码似乎也就那样,再一看哦似乎是有点东西,仔细一看,这道题不简单!
它结合了以下知识点
- 1.变量作用域
- 2.列表推导式
- 3.匿名函数
- 4.闭包函数
- 5.for循环对函数的迭代调用
- 6.闭包函数的调用
1.变量作用域
看一个例子
a = 10
def test():
a += 1
print(a)
test()
Python的规则是,如果在函数内部要修改一个变量,那么这个变量需要是内部变量,除非你用global声明了它是外部变量。很明显,我们没有在函数内部定义变量a,所以会弹出局部变量在未定义之前就引用的错误。
2.列表推导式
看一个例子
>>> result = [x+x for x in range(1,10)]
>>> result
[2, 4, 6, 8, 10, 12, 14, 16, 18]
列表推导式要这么理解,首先执行for循环,对于每一个x,代入x*x中进行运算,将运算结果逐一添加到一个新列表内,循环结束,得到最终列表。它相当于下面的代码:
>>> result = []
>>> for i in range(1, 10):
result.append(i+i)
>>> print(result)
[2, 4, 6, 8, 10, 12, 14, 16, 18]
3.匿名函数
看一个例子
>>> result = lambda a,b:a+b
>>> print(result)
<function <lambda> at 0x0000024BAB54E400>
>>> res = result(0,10)
>>> print(res)
10
匿名函数只能有一个表达式,不用也不能写return语句,表达式的结果就是其返回值。 匿名函数没有函数名字,不必担心函数名冲突,节省字义空间。匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。只有调用这个匿名函数,它才会执行冒号后面的代码,这也是函数的执行法则,只有被调用时,函数内部的命名空间才会生效,在被调用之前它就是一个函数名指向的内存地址而已。它相当于下面的代码
>>> def result(a,b):
return a+b
>>> result(0,10)
10
4.闭包函数
根据上面的分析现在可以将上面的列表推断式
lis = []
for i in range(10):
res = lambda x:i+x
lis.append(res)
当前函数引用到上一层函数的局部命名空间的变量时就会触发闭包规则。我们说触发了闭包的函数叫做闭包函数,但是要注意一点:只有当调用闭包函数的时候它才会去引用外层函数的变量,因为在调用闭包函数之前,闭包内部的命名空间还不存在。
匿名函数lambda x:i+x引用了外层函数的命名空间内的变量i,所以它触发了闭包规则,然后外层函数的返回值是一个列表,这个列表的元素为十个闭包函数名指向的内存地址,虽然for i in range(10)这段代码里面的i的值分别被赋予了十个值,但是闭包函数res并没有引用这十个值,因为闭包函数此时此刻还没有被真正调用,列表推导式仅仅是把十个匿名函数指向的内存地址保存在了一个列表里,因为没有调用,所以匿名函数内部的代码并没有执行,也就不存在引用。
所以外部函数的返回值就是这样的一个列表:[lambda x:i+x,lambda x:i+x,.....],它相当于下面的代码
def waibu():
lis =[]
for i in range(10):
def bibao(i):
return x + i
lis.append(bibao)
return lis
5.for循环对函数的迭代调用
print(result[0](10)),这条语句到底是干嘛的呢?其实它干的事情只有一个,那就是遍历了waibu函数()返回的列表
注意:此时此刻匿名函数才真正被调用了,然后它会引用外层命名空间的变量
6.闭包函数的调用
把这个列表推导式拆开的话 它应该是下面这个样子,结果完全一样:
def waibu():
lis =[]
for i in range(10):
def bibao(x):
return i + x
lis.append(bibao)
return lis
result = waibu()
print(result[2](10))
其实还等价于
def multipliers():
squares = []
for i in range(10):
res = lambda x:i+x
squares.append(res)
return squares
squares2 = []
for m in multipliers():
squares2.append(m(10))
print(squares2)