Python:函数式编程(五):lambda 表达式和偏函数

阳光穿透心脏的1/2处 2023-07-23 14:58 51阅读 0赞

lambda 表达式

lambda 表达式是 Python 中创建匿名函数的一个特殊语法,匿名函数顾名思义就是指:是指一类无需定义标识符(函数名)的函数或子程序。
lambda 表达式返回的是一个函数,一个匿名函数。
例如我们定义求积函数的一般语法如下:

  1. def multiply(a, b):
  2. return a * b

而我们使用我们的 lambda 表达式是这样的:

  1. f = lambda a, b: a*b

然后调用 multiply(5, 3) 和调用 f(5, 3) 是等效的。

lambda 的语法:

  1. lambda argument_list: expression

这个形式等效于:

  1. def function_name(argument_list):
  2. expression

容易看出使用 lambda 表达式的特点就是不用给函数命名,也就是所谓的匿名函数。

lambda 的特点:

  • 匿名函数是匿名的:所谓匿名函数,通俗地说就是没有名字的函数。lambda 函数没有名字。
  • 匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。
  • 匿名函数有输入和输出:输入是传入到参数列表 argument_list 的值,输出是根据表达式 expression 计算得到的值。
  • 匿名函数有个限制,就是只能有一个表达式,不用写 return,返回值就是该表达式的结果。
  • 匿名函数一般功能简单:单行 expression 决定了 lambda 函数不可能完成复杂的逻辑,只能完成非常简单的功能
  • 匿名函数本身缺少名称和文档, 意味着了解它们功能的唯一方式就是读代码

lambda 的用法:

最常见的用法:将 lambda 函数作为参数传递给其他函数。
例子:

  1. s = [('a', 3), ('b', 2), ('c', 1)]
  2. print(sorted(s, key=lambda x: x[0]))
  3. print(sorted(s, key=lambda x: x[1]))

结果如下:
在这里插入图片描述
可以看到这里的 lambda 函数作为 sorted 函数的参数,第一个表示按照列表每个元素的第一个元素排序,而第二个表示按照列表每个元素的第二个元素排序。类似的用法还在 map, reduce,filter 中使用。

lambda 的争议:

lambda 的使用时存在一些争议的:

  1. 一些人认为使用 lambda,是代码更加简洁,更加符合 python 的哲学。
  2. 另一些认为,使用 lambda 语句有时候会使代码可读性降低,不利于维护。

偏函数:

引入偏函数

Python 的 functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。

int() 函数可以把字符串转换为整数,当仅传入字符串时,int() 函数默认按十进制转换:
例如:

  1. int('12345')

结果是 12345
但 int() 函数还提供额外的 base 参数,默认值为 10。如果传入 base 参数,就可以做N进制的转换:

  1. int('12345', base=8)
  2. int('12345', 16)

结果分别是:5349 和 74565。
假设要转换大量的二进制字符串,每次都传入 int(x, base=2) 非常麻烦,于是,我们想到,可以定义一个int2() 的函数,默认把 base=2 传进去:

  1. def int2(x, base=2):
  2. return int(x, base)

这样,我们转换二进制就非常方便了。
functools.partial 就是帮助我们创建一个偏函数的,不需要我们自己定义 int2(),可以直接使用下面的代码创建一个新的函数 int2:

  1. import functools
  2. int2 = functools.partial(int, base=2)
  3. int2('1000000')
  4. int2('1010101')

所以,简单总结 functools.partial 的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

偏函数等效于设置默认值

注意到上面的新的 int2 函数,仅仅是把 base 参数重新设定默认值为 2,但也可以在函数调用时传入其他值:

  1. int2('1000000', base=10)

偏函数完整形式

最后,创建偏函数时,实际上可以接收函数对象、*args 和 **kw 这 3 个参数,当传入:

  1. new_func = functools.partial(func, *args, **keywords)

partial 一定接受三个参数:

  1. func: 需要被扩展的函数,返回的函数其实是一个新的类似于原来 func 的函数 new_func
  2. *args: 可变长参数;
  3. **kwargs: 关键字参数;

partial 一定接受三个参数

  1. int2 = functools.partial(int, base=2)

实际上固定了 int( ) 函数的关键字参数 base,也就是:

  1. int2('10010')

相当于:

  1. kw = { 'base': 2 }
  2. int('10010', **kw)

当传入:

  1. max2 = functools.partial(max, 10)

实际上会把 10 作为 *args 的一部分自动加到左边,也就是:

  1. max2(5, 6, 7)

相当于:

  1. args = (10, 5, 6, 7)
  2. max(*args)

偏函数体现函数式编程的方面:函数作为偏函数的参数,函数作为偏函数的返回值。

偏函数参考:偏函数

发表评论

表情:
评论列表 (有 0 条评论,51人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Lambda表达式函数接口

    一 点睛 Lambda表达式的类型,也称为“目标类型”,Lambda表达式的目标类型必须是函数式接口。函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法、