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

lambdex - 让 Python 支持更复杂的 lambda 匿名函数表达式

  •  4
     
  •   hsfzxjy ·
    hsfzxjy · 2021-02-10 14:19:56 +08:00 · 2049 次点击
    这是一个创建于 1142 天前的主题,其中的信息可能已经有所发展或是发生改变。

    先放出 Github 地址: https://github.com/hsfzxjy/lambdex

    大概一个月前有一个奇思妙想:说到匿名函数,Python 虽有 lambda 表达式,但与其他语言如 Rust 的闭包或是 JS 的箭头函数相比还是过于简单了。其函数体仅支持单一表达式,不支持更复杂的语句。我想对此做一些扩展,使 Python 支持更复杂的匿名函数。于是便有了 lambdex 。

    目前 lambdex 支持写出类似如下的代码(以递归计算 Fibonacci 数列为例):

    from lambdex import def_
    def_(lambda n: [
        if_[n <= 0] [
            raise_[ValueError(f'{n} should be positive')]
        ],
        if_[n <= 2] [
            return_[1]
        ],
        return_[callee_(n - 1) + callee_(n - 2)]  # Recursion
    ])(10)  # 55
    

    lambdex 以一种非侵入式的方式在运行时转写 AST 并编译成字节码,并将字节码缓存以供后续使用,因此只有首次编译的 overhead 。同时,lambdex 还提供了一个内置的 Formatter,用于格式化含有匿名函数的代码。

    也许你会说“这个库没有工程应用价值” “这个库不 Pythonic” “这个语法不够函数式”等等。本人认同这些观点。

    但作为一个语法扩展的实验性项目,lambdex 应该算是同类中较为完备的。lambdex 本身有很大的可玩性,并为实现其他语言中的一些函数式范式提供了可能。

    lambdex 确实不 Pythonic,但对于不看重 Pythonic 的用户,这是个好的尝试。同时 lambdex 对标的是如 Rust 或 JS 中的匿名函数,期望在匿名函数中提供更完备的 imperative programming 体验,并无意向 Haskell 等看齐。

    最后个人认为构建这个库本身就是一件很有趣的事情。在这个过程中本人接触到了 CPython 底层的许多细节,同时也在不断思考如何更干净地实现各种逻辑。这是非常有意义的一件事。

    欢迎各位试用并提 Issues !

    16 条回复    2021-02-11 14:23:50 +08:00
    abersheeran
        1
    abersheeran  
       2021-02-10 15:21:21 +08:00
    很酷!我详细看看。另外一提,在类似于循环中使用 def_(lambda x: ...) 会不会反复创建匿名函数对象?
    hsfzxjy
        2
    hsfzxjy  
    OP
       2021-02-10 15:29:12 +08:00
    @abersheeran 不会哦,只有第一次循环时会编译,其他时候会利用缓存
    abersheeran
        3
    abersheeran  
       2021-02-10 15:35:46 +08:00
    @hsfzxjy 那么这个缓存的失效时机是?
    abersheeran
        4
    abersheeran  
       2021-02-10 15:38:10 +08:00
    能否开开 GitHub 的 discussions,v2ex 的提醒我有时候会看不到,GitHub 的提醒比较及时。另外在 GitHub 上讨论也便于后来者查看。
    nuistzhou
        5
    nuistzhou  
       2021-02-10 15:41:37 +08:00 via iPhone
    额,lambda 本身不就是为了方便实现简单功能而无需单独定义一个 method 吗?一家之言仅供讨论哈
    hsfzxjy
        6
    hsfzxjy  
    OP
       2021-02-10 15:42:53 +08:00
    @abersheeran #3 在整个运行时中不会失效。被缓存的仅仅是函数的 code object,不包含函数的上下文,因此是比较轻量的。循环中调用 def_,或者是在一个函数中返回 def_,都会复用同一个 code object 。
    hsfzxjy
        7
    hsfzxjy  
    OP
       2021-02-10 15:44:20 +08:00
    @nuistzhou #5 你说的有道理,但是有时候我们可能需要一些复杂却又是一次性的逻辑,这时 lambda 就显得有些捉襟见肘了。
    abersheeran
        8
    abersheeran  
       2021-02-10 15:44:58 +08:00
    @hsfzxjy 明白了。
    122006
        9
    122006  
       2021-02-10 16:09:24 +08:00
    我也写了一个 java 支持内插字符串的语法糖。
    一堆人畏之如虎。推广真的太难了
    hsfzxjy
        10
    hsfzxjy  
    OP
       2021-02-10 16:19:38 +08:00
    @abersheeran #4 刚看到这条,已开了 Discussions ~
    hsfzxjy
        11
    hsfzxjy  
    OP
       2021-02-10 16:21:39 +08:00
    @122006 #9 哈哈,所以我选择在 README 和推广帖里先自我批评一下
    abersheeran
        12
    abersheeran  
       2021-02-10 16:42:41 +08:00   ❤️ 3
    @122006 嗨,有趣的东西不要直接给中国程序员群体推。去国外推,在国外火了,自然有人上赶着给你搞汉化。

    这是我看华人最强开源项目运营大师(作品:Vue )的一些经历和发言。加之自己的观察得出来的观点,或有错漏,但不妨一试。
    hsfzxjy
        13
    hsfzxjy  
    OP
       2021-02-10 21:11:58 +08:00
    刚添加了新的特性,完整支持了 async/await 系列的语法。同时也添加了若干可选的语言扩展,如 Rust 风格的 await,自动返回最后一个表达式。
    shniubobo
        14
    shniubobo  
       2021-02-11 09:59:14 +08:00 via Android
    @hsfzxjy #7 既然复杂了,为什么不直接定义一个函数呢?即便是一次性的逻辑,也完全可以单独定义一个函数;这样既可以把这个逻辑单独分开,让代码更清晰,还可以在 traceback 里面显示函数名。
    hsfzxjy
        15
    hsfzxjy  
    OP
       2021-02-11 14:21:36 +08:00
    @shniubobo #14

    一个场景是在写高阶函数时,我们通常要将被返回的写成 nested function——这种方式见仁见智,但个人感觉是不够直观的。

    此外,对于**稍微**复杂点的 predicate,比如稍微多一两个分支,或者需要暂存某些中间结果,这种放入 lambda 会降低可读性甚至放不进 lambda,单独存一个具名函数个人觉得没有必要。此外还有 GUI 编程中,如果 event handler 的逻辑简单但不能表达成 expression,lambda 不使用,但也没必要单独拎一个函数。这些都是 lambdex 优于 lambda 的可能场景。

    至于 traceback 和 函数名,lambdex 是可以做到的。lambdex 的编译和运行时错误可以精确定位到相应的行,未来也会支持让函数具名(但这个名字不会暴露到它的父级作用域),可以说 debug 的体验和普通函数是一致的。

    个人认为,Python 官方推荐的范式是好的,但也没必要把相关的 anti-patterns 视为洪水猛兽,有时它们会是更优的选择。当然个人也不提倡滥用某个 pattern,这个库也不是为了这个目的提出来的,只是希望能在有人需要它们时提供可行性。
    hsfzxjy
        16
    hsfzxjy  
    OP
       2021-02-11 14:23:50 +08:00
    @hsfzxjy #15 lambda 不使用 -> lambda 不适用
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3080 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 12:45 · PVG 20:45 · LAX 05:45 · JFK 08:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.