Python lambda表达式学习主要以在代码的形式来记录,每行代码都实际运行过,如有疑问或更好的实现方法,欢迎留言,非常感谢,大家共同学习!
lambda表达式常用来声明匿名函数,即没有函数名字的临时使用的小函数,常用在临时需要一个类似于函数的功能但又不想定义函数的场合。
lambda表达式只可以包含一个表达式,不允许包含其他复杂的语句,但在表达式中可以调用其他函数,该表达式的计算结果相当于函数的返回结果。
Python中 lambda表达式的特点:
-
lambda表达式可以接受任意数量的参数,但函数只能包含一个表达式。表达式是lambda函数执行的一段代码,它可以返回任何值,也可以不返回任何值。
-
lambda表达式可以返回函数对象。
语法
lambda argument: expression
我们可以有很多个参数,但是只能有一个表达式。lambda操作符不能有任何声明,它返回一个函数对象
1. 简单小例子
f = lambda x, y, z: x + y + z #也可以给 lambda 表达式起个名字
print(f(1,2,3))
输出:6
2. 支持默认值参数
g = lambda x, y = 1, z = 2: x + y + z
print(g(1)) #y z 使用默认值
输出:4
print(g(1,y=3,z=4)) #调用时使用关键字参数赋值
输出:8
3. 在可变类型中使用lambda表达式
lst = [(lambda x:x**2), (lambda y:y**2), (lambda z:z**2)]
print(lst[0](2), lst[1](3), lst[2](3))
输出:4 9 9
dic = {'f1':(lambda :1 + 2), 'f2':(lambda :2 + 3), 'f3':(lambda :3 + 4)}
print(dic['f1'](), dic['f2'](), dic['f3']())
输出:3 5 7
4. lambda表达式作为函数参数
def myMap(lst, value): #序列的每一项都加value
return map(lambda item: item + value,lst)
print(list(myMap(range(5), 3)))
输出:[3, 4, 5, 6, 7]
5. 提取大整数每位上的数字
tmp = random.randint(1,1e10)
print('tmp为:',tmp)
输出:tmp为: 8428804196
print(list(map(int,str(tmp))))
输出:[8, 4, 2, 8, 8, 0, 4, 1, 9, 6]
6. 用lambda表达式创建一个求元素个数的匿名函数
element_count = lambda lst : len(lst)
print(element_count(range(5)))
输出:5
7. lambda变量作用域问题解析
r = []
for x in range(5):
r.append(lambda: x**2) #列表r追加元素
print(r)
输出:[<function <lambda> at 0x0000023C9B7E7B70>, <function <lambda> at 0x0000023C9B7E7BF8>, <function <lambda> at 0x0000023C9B7E7C80>, <function <lambda> at 0x0000023C9B7E7D08>, <function <lambda> at 0x0000023C9B7E7D90>]
print(x)
输出:4
print(r[0]()) #输出:16
print(r[1]()) #输出:16
print(r[2]()) #输出:16
print(r[3]()) #输出:16
为什么无论r的下标取多少,结果都是16(4**2)呢?
原因在lambda表达式写的有问题,此处涉及到变量作用域的问题!
首先要知道:这是一个嵌套函数,for循环里嵌套了lambda表达式,for循环为外部函数,lambda为内部函数。
最关键的点:函数内部可以读取该函数外部的变量,但函数外部无法读取该函数内部定义的变量
其次要明白r到底在内存中存储的是什么,这是打印的r:
为了便于观看,我做了下格式化处理:
[
<function <lambda> at 0x000001660F848AE8>,
<function <lambda> at 0x000001660F848B70>,
<function <lambda> at 0x000001660F848BF8>,
<function <lambda> at 0x000001660F848C80>,
<function <lambda> at 0x000001660F848D08>
]
由结果可见,列表r的元素都是lambda表达式组成的,存储的是一组内部函数,这也证明了:lambda表达式的返回值是一个函数对象。
当执行r[0]()
,会执行
<function <lambda> at 0x000001660F848AE8>
即lambda:x**2
,因此x的值就决定了最后的输出结果。
因为x是在for循环(外部函数)里定义的,当for循环都执行完或,x的值为4。
#选自上文的代码
print(x)
输出:4
最后我们看下要输出的函数:
print(r[0]()) #输出:16
print(r[1]()) #输出:16
print(r[2]()) #输出:16
print(r[3]()) #输出:16
当执行r[0]()
时,首先会寻找内部函数自身(即lambda表达式)是否定义了x变量,没有则向上一层(for循环)找。
for循环里定义了变量x,当for循环全部执行完后,x=4。此时找到了x变量,就停止寻找,返回x
所以r[0]()
、r[1]()
、r[2]()
、r[3]()
…的值都是16。
那如何修复这个问题?
执行r[0]()
时,让在内部函数自身(即lambda表达式)找到属于自己的变量就OK!
所以做以下改造:
tmp = []
for y in range(10):
tmp.append(lambda n = y: n**2)
print(tmp[0](2)) #即 2**2
输出:4
print(tmp[0](10)) #即10**10
输出:100