Python lambda表达式学习

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     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值