V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
Thoxvi
V2EX  ›  分享创造

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

  •  
  •   Thoxvi ·
    thoxvi · 2018-05-22 20:31:47 +08:00 · 2242 次点击
    这是一个创建于 2159 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址

    希望大佬们不吝啬 Star 鼓励一下 ;-)

    为了解决什么问题?

    举个例子,当你在原生 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. 类似于 filtermap 之类的操作,只能是嵌套的,而不能是链式调用
    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 或者发邮件到 [email protected] 联系我。

    ; )

    函数名命名规范问题

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

    silhouette
        1
    silhouette  
       2018-05-22 20:38:31 +08:00 via Android
    6666
    Arnie97
        2
    Arnie97  
       2018-05-22 20:44:32 +08:00 via Android
    之前有一个 Shell 管道画风的库,和这个库功能较为类似: https://github.com/0101/pipetools
    Thoxvi
        3
    Thoxvi  
    OP
       2018-05-22 20:48:56 +08:00
    @Arnie97 卧槽我去瞅瞅代码,看看能引进啥
    hourann
        4
    hourann  
       2018-05-22 21:09:28 +08:00 via iPhone
    链式调用确实是个痛点…
    Thoxvi
        5
    Thoxvi  
    OP
       2018-05-22 21:12:16 +08:00
    @hourann 是的,痛了好久终于忍不住想治治了。。。
    msg7086
        6
    msg7086  
       2018-05-22 23:17:18 +08:00
    这是把 Python 写出了 Ruby 的风格吗……
    Thoxvi
        7
    Thoxvi  
    OP
       2018-05-22 23:30:44 +08:00
    @msg7086 设计思路是偏向于混合 Js 和 Kotlin 的,Python 完全不支持代码块啊。。。
    inflationaaron
        8
    inflationaaron  
       2018-05-22 23:45:45 +08:00
    对于函数式来说 point free style 会更好一点
    msg7086
        9
    msg7086  
       2018-05-23 00:26:53 +08:00
    @Thoxvi 有半残废的 Lambda 嘛。
    Thoxvi
        10
    Thoxvi  
    OP
       2018-05-23 07:44:20 +08:00 via Android
    @msg7086 没错…的确是半残废…
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1022 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 19:27 · PVG 03:27 · LAX 12:27 · JFK 15:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.