匿名函数:lambda
在Python中除了def语句之外还提供了另一种生成函数对象的表达式形式。(lambda是希腊字符λ,Haskell语言的符号就是λ,在这里我要安利大家都学习一下Haskell,这会对我们以后编程有很大的帮助)。lambda这个表达式创建1一个之后能够调用的函数,但是它返回了一个函数而不是将这个函数赋值给一个变量名。这也就是lambda为什么叫匿名函数的原因。实际上,lambda常常以一种行内进行函数定义的形式使用,或者用作推迟执行一些代码。
lambda表达式
lambda的一般表现形式是关键字lambda,之后是一个或多个参数,紧跟的是一个冒号,之后是一个表达式:
lambda argument1, argument2,... argumentN: expression using arguments
- lambdas是一个表达式,而不是一个语句。所以lambda能够出现在Python语法不允许def出现的地方
- lambda的主体的一个单一的表达式,而不是一个代码块。
除了这些差别,def和lambda都能够做同样种类的工作就像下面的例子所示:
#示例1
>>> def func(x, y, z):
... return x + y + z
...
>>> func(3, 4, 5)
12
>>> f = lambda x, y, z: x + y + z
>>> f(3, 4, 5)
12
这里的f被赋值给一个lambda表达式创建的函数对象。
默认参数也能够在lambda参数中使用,就像在def中使用一样
#示例2
>>> x = lambda a="I", b="Love" , c="You": a + b + c
>>> x()
'ILoveYou'
>>> x('e')
'eLoveYou'
为什么要使用lambda
一般来说,lambda起到了一种函数速写的作用,允许在使用的代码内嵌入一个函数的定义。
lambda通常用来编写跳转表,也就是行为的列表或字典,能够按照需要执行相应的动作。如示例3所示:
#示例3
L = [lambda x: x ** 2,
lambda x: x ** 3,
lambda x: x ** 4]
for f in L:
print(f(2)) #prints 4, 8, 16
print(L[0](3)) #prints 9
当需要把小段的可执行代码编写进def语句从语法上不能编写进的地方时,lambda表达式作为def的一种速写来说是最为有用的。如示例3,可以通过在列表常量中嵌入lambda表达式创建一个含有3个函数的列表。一个def是不会在列表常量中工作的,因为def是一个语句而不是一个表达式。对等的def代码可能需要在想要使用的环境之外有临时性函数名称和函数定义。
#示例4
def f1(x): return x ** 2
def f2(x): return x ** 3
def f3(x): return x ** 4
L = [f1, f2, f3]
for f in L:
print(f(2)) #prints 4, 8, 16
print(L[0](3)) #prints 9
不要让Python代码变得晦涩难懂
由于lambda的主体必须是单个表达式,由此仅能将有限的逻辑封装到一个lambda中。
例如,如果你想在lambda函数中进行print,那么就直接编写sys.stdout.write(str(x)+'\n')这个表达式,而不是使用print(x)这样的语句。类似的,要在一个lambda中嵌套逻辑,可以使用if/else三元表达式,或者对等的但需要有些技巧的and/or组合。
示例5
if a:
b
else:
c
b if a else c
((a and b) or c)
这些技巧最后在万不得已的情况下使用。不然就可能变成晦涩难懂的Python代码。
嵌套lambda和作用域
lambda是嵌套函数作用域查找的最大的受益者。例如示例6所示,lambda出现在def中,并且在上层函数调用的时候,嵌套的lambda能够获得到上层函数作用域中的变量名x的值。
示例6
>>> def action(x):
... return (lambda y: x + y)
...
>>> act = action(99)
>>> act
<function action.<locals>.<lambda> at 0x000001CFBE6316A8>
>>> act(2)
101
如果我们把示例6中的def换成一个lambda:
示例7
>>> action = (lambda x: (lambda y: x + y))
>>> act = action(99)
>>> act(3)
102
>>> ((lambda x: (lambda y: x + y))(99))(4)
103
这里嵌套的lambda结构让函数在调用时创建了一个函数。无论以上哪种情况,嵌套的lambda代码都能够获取在上层lambda函数中的变量x。虽然这可以正常运行,但是这种代码让人相当费解。所有对于可读性的要求,通常来说最好避免使用嵌套lambda(可以装emmm为什么不用?)。