Python:函数式编程(五):lambda 表达式和偏函数
lambda 表达式
lambda 表达式是 Python 中创建匿名函数的一个特殊语法,匿名函数顾名思义就是指:是指一类无需定义标识符(函数名)的函数或子程序。
lambda 表达式返回的是一个函数,一个匿名函数。
例如我们定义求积函数的一般语法如下:
def multiply(a, b):
return a * b
而我们使用我们的 lambda 表达式是这样的:
f = lambda a, b: a*b
然后调用 multiply(5, 3) 和调用 f(5, 3) 是等效的。
lambda 的语法:
lambda argument_list: expression
这个形式等效于:
def function_name(argument_list):
expression
容易看出使用 lambda 表达式的特点就是不用给函数命名,也就是所谓的匿名函数。
lambda 的特点:
- 匿名函数是匿名的:所谓匿名函数,通俗地说就是没有名字的函数。lambda 函数没有名字。
- 匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。
- 匿名函数有输入和输出:输入是传入到参数列表 argument_list 的值,输出是根据表达式 expression 计算得到的值。
- 匿名函数有个限制,就是只能有一个表达式,不用写 return,返回值就是该表达式的结果。
- 匿名函数一般功能简单:单行 expression 决定了 lambda 函数不可能完成复杂的逻辑,只能完成非常简单的功能
- 匿名函数本身缺少名称和文档, 意味着了解它们功能的唯一方式就是读代码
lambda 的用法:
最常见的用法:将 lambda 函数作为参数传递给其他函数。
例子:
s = [('a', 3), ('b', 2), ('c', 1)]
print(sorted(s, key=lambda x: x[0]))
print(sorted(s, key=lambda x: x[1]))
结果如下:
可以看到这里的 lambda 函数作为 sorted 函数的参数,第一个表示按照列表每个元素的第一个元素排序,而第二个表示按照列表每个元素的第二个元素排序。类似的用法还在 map, reduce,filter 中使用。
lambda 的争议:
lambda 的使用时存在一些争议的:
- 一些人认为使用 lambda,是代码更加简洁,更加符合 python 的哲学。
- 另一些认为,使用 lambda 语句有时候会使代码可读性降低,不利于维护。
偏函数:
引入偏函数
Python 的 functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。
int() 函数可以把字符串转换为整数,当仅传入字符串时,int() 函数默认按十进制转换:
例如:
int('12345')
结果是 12345
但 int() 函数还提供额外的 base 参数,默认值为 10。如果传入 base 参数,就可以做N进制的转换:
int('12345', base=8)
int('12345', 16)
结果分别是:5349 和 74565。
假设要转换大量的二进制字符串,每次都传入 int(x, base=2) 非常麻烦,于是,我们想到,可以定义一个int2() 的函数,默认把 base=2 传进去:
def int2(x, base=2):
return int(x, base)
这样,我们转换二进制就非常方便了。
functools.partial 就是帮助我们创建一个偏函数的,不需要我们自己定义 int2(),可以直接使用下面的代码创建一个新的函数 int2:
import functools
int2 = functools.partial(int, base=2)
int2('1000000')
int2('1010101')
所以,简单总结 functools.partial 的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
偏函数等效于设置默认值
注意到上面的新的 int2 函数,仅仅是把 base 参数重新设定默认值为 2,但也可以在函数调用时传入其他值:
int2('1000000', base=10)
偏函数完整形式
最后,创建偏函数时,实际上可以接收函数对象、*args 和 **kw 这 3 个参数,当传入:
new_func = functools.partial(func, *args, **keywords)
partial 一定接受三个参数:
func: 需要被扩展的函数,返回的函数其实是一个新的类似于原来 func 的函数 new_func;
*args: 可变长参数;
**kwargs: 关键字参数;
partial 一定接受三个参数
int2 = functools.partial(int, base=2)
实际上固定了 int( ) 函数的关键字参数 base,也就是:
int2('10010')
相当于:
kw = { 'base': 2 }
int('10010', **kw)
当传入:
max2 = functools.partial(max, 10)
实际上会把 10 作为 *args 的一部分自动加到左边,也就是:
max2(5, 6, 7)
相当于:
args = (10, 5, 6, 7)
max(*args)
偏函数体现函数式编程的方面:函数作为偏函数的参数,函数作为偏函数的返回值。
偏函数参考:偏函数
还没有评论,来说两句吧...