让 Python 的高阶函数支持链式调用[实用库/轮子]

时间:2022-07-27
本文章向大家介绍让 Python 的高阶函数支持链式调用[实用库/轮子],主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

为了解决什么问题?

举个例子,当你在原生 Python 里使用函数式编程的时候,不免会写出如下代码:

  # 先给所有元素 +1,
  # 再筛选大于 4 的元素,
  # 打印,
  # 再让所有元素 +1,
  # 最后让 l 变成 List,方便后续的操作
  
  l = [1, 2, 3, 4, 5]
  l = filter(lambda x: x   4, map(lambda x: x + 1, l))
  l = list(l)
  print(l)
  # [5, 6]
  
  l = list(map(lambda x: x + 1, l))
  assert l==[6, 7]

这里有几个让人不舒服的地方

  1. 类似于?filter?和?map?之类的操作,只能是嵌套的,而不能是链式调用
  2. list?化要也需要嵌套使用
  3. 打印需要中断操作、保存现场、打印、恢复现场等一系列的操作
  4. Python 对高阶函数库的支持不如像 Kotlin 之类的那么精细(虽然自己可以实现,但是颇为麻烦)

如何使用?

fc?库能够优雅地解决以上问题,而你只需要在环境终端里输入

$ pip install fc

然后上述的代码就可以改成:

from fc import Fc

# 建议用括号 () 把链式的 Fc 包起来,就可以实现多行链式调用了(虽然有点丑,但是是无可奈何的。。。

l = (
  Fc([1, 2, 3, 4, 5])
    .map(lambda x: x + 1)
    .filter(lambda x: x   4)
    .print()  # [5, 6]
    .map(lambda x: x + 1)
    .done()
)
assert l == [6, 7]

并且当你不需要 print 的时候,只需要简单在前面加上一个?#?即可轻松注释。

注:Fc 不会改变传入的 Iterable,即以只读的形式对待传入的参数,每次链式都会创建一个新的 Fc(时间复杂度为 O(1),可以忽略不计),满足函数无副作用的思想。

性能问题?不用担心

fc 考虑了性能上的优化策略,所有的支持链式的 Fc 的类成员函数基本上都是使用生成器的方式返回(yield),即实现了惰性求值,优化了时间和空间效率,只有个别函数由于实现原因(需要从后向前计数等)会转换成数组,并且这种函数都会被标注在文档上,方便进行性能排查。

当然,如果你有任何建议(不限于性能优化等)都可以提 issue 或者发邮件到 A@Thoxvi.com 联系我。

; )

函数名命名规范问题

项目默认使用的是驼峰命名,但由于 Python 一贯是使用下划线命名,所以 fc 提供了一个?Fc_?的类,除了把驼峰式例如?getAfter?变成了?get_after?以外,功能上没有任何差别,可以放心使用。(不过因为是动态生成的,所以 IDE 可能不会提供自动补全,所以如果不是刚需的话,不是特别建议手撸下划线式(当然不用太在意这个,功能、性能又不会有影响,就是怕手误打错而已))。

文档下载:Function-Chain-Python-master