V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
abersheeran
V2EX  ›  Python

六行代码实现 Python 管道

  •  7
     
  •   abersheeran · 2021-01-10 17:14:24 +08:00 · 12745 次点击
    这是一个创建于 1407 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不多说,直接上代码。

    from functools import partial
    
    class F(partial):
        def __ror__(self, other):
            if isinstance(other, tuple):
                return self(*other)
            return self(other)
    

    使用样例。

    range(10) | F(filter, lambda x: x % 2) | F(sum)
    

    更详细的前因后果介绍,可以看 https://aber.sh/articles/Python-Pipe/ ,实在是懒得复制到 V2EX 调样式了。有兴趣的就看看,没兴趣的就复制代码去用就完事。

    小小的得瑟一下,这是最近几天写的最满意、最有用的代码。妙手偶得之~

    第 1 条附言  ·  2021-01-12 15:19:15 +08:00

    应某位回复者的要求,已经发布到 PyPi,顺便在 GitHub 建了个库,写了使用说明。https://github.com/abersheeran/only-pipe

    稍微解决了一下好几个人觉得困扰的 tuple 判断。现在在库里,F 只会传一个参数,如果你想让 tuple 被拆解,应当使用 FF。是否解包,控制权交给程序员,而不是代码本身。

    增加了一个功能,可以把 Freduce 释放到全局,就像 map/filter 一样直接用就行。

    import pipe
    import functools
    
    pipe.set_global(pipe.F, pipe.FF, functools.reduce)
    
    assert range(10) | F(filter, lambda x: x % 2) | F(sum) == 25
    assert (1, 2, 3) | F(sum) == 6
    
    assert (1, 2) | FF(lambda x, y: x + y) == 3
    
    assert range(10) | F(reduce, lambda x, y: x + y) == 45
    
    第 2 条附言  ·  2021-01-12 16:48:57 +08:00

    有回复者提到的 Filter = F(filter) 的类似写法,可通过手动柯里化实现。

    from functools import reduce
    from pipe import F
    
    
    def fp(func):
        def _(*args, **kwargs):
            return F(func, *args, **kwargs)
        return _
    
    
    Filter = fp(filter)
    Map = fp(map)
    Reduce = fp(reduce)
    
    range(100) | Filter(lambda x: x % 2) | Map(lambda x: x * x) | Reduce(lambda x, y: x + y)
    

    https://github.com/abersheeran/only-pipe/discussions/1

    122 条回复    2021-02-19 02:25:18 +08:00
    1  2  
    msg7086
        1
    msg7086  
       2021-01-10 17:24:29 +08:00   ❤️ 1
    (虽然我知道这很煞风景,但是我真的忍不住想要吐槽一句,你这不就是把 Python 写成了 Ruby 吗……)
    msg7086
        2
    msg7086  
       2021-01-10 17:27:20 +08:00
    顺带提一句,如果让我来写 Python 的话,我可能还是选择把代码写成 list comprehension (可能需要推倒两次)。
    不写 map reduce 是因为怕被 Python 用户吐槽不够 Pythonic 。
    abersheeran
        3
    abersheeran  
    OP
       2021-01-10 17:37:32 +08:00
    @msg7086 四年 Python 老玩家了,谁敢说我不代码 Pythonic 我就怼死他,我写 C 都 Python 味儿了。😀

    Ruby 是真没用过,我甚至没有用过任何一门纯粹的函数式编程语言。管道我还是从 Shell 学到的,虽然 Shell 我只是用到 | grep 这种地步。但并不妨碍我真诚的觉得管道很好用。在我几个函数式教徒朋友给我推销的函数式编程概念里,柯里化和管道是我认为唯二可在工业代码里大量使用的。
    msg7086
        4
    msg7086  
       2021-01-10 17:48:52 +08:00
    我之前写任务依赖管理的时候也是把 pipe 拿来用了。
    class Tasks < Array
    def |(op)
    op.call(sources: self)
    end
    end
    类似这么个结构,感觉和你的差不多。
    自己发明 DSL 确实很有成就感。
    Leigg
        5
    Leigg  
       2021-01-10 17:54:14 +08:00 via iPhone
    有半年没有写 py 了,现在都进化到这个程度了吗?
    Leigg
        6
    Leigg  
       2021-01-10 17:55:14 +08:00 via iPhone
    我擦,原来是 magic method 。还以为是 shell 语法呢。
    stdout
        7
    stdout  
       2021-01-10 18:06:01 +08:00
    很花哨实用。
    python4
        8
    python4  
       2021-01-10 18:06:18 +08:00   ❤️ 1
    等 python4 发布的时候就作为 feature 吧。
    SjwNo1
        9
    SjwNo1  
       2021-01-10 18:20:54 +08:00
    是很优雅,但不够语义化 - . -
    whileFalse
        10
    whileFalse  
       2021-01-10 18:41:38 +08:00
    不错 很优雅!
    abersheeran
        11
    abersheeran  
    OP
       2021-01-10 19:08:27 +08:00 via Android
    @python4 Guido:I don't like it.
    ferock
        12
    ferock  
       2021-01-10 19:09:25 +08:00 via iPhone
    学习
    Jirajine
        13
    Jirajine  
       2021-01-10 19:22:37 +08:00 via Android
    不错,可以发布到 pypi
    abersheeran
        14
    abersheeran  
    OP
       2021-01-10 19:28:57 +08:00 via Android   ❤️ 1
    @Jirajine 请不要把 npm 行为带到 Python 社区。满打满算六行代码,这也需要 PyPi 走一下?复制粘贴它不香吗。我要是真发布了,setup.py 比源码还大。
    abersheeran
        15
    abersheeran  
    OP
       2021-01-10 19:31:43 +08:00 via Android
    @SjwNo1 如果你认为运算符不够语义化,建议开新文,炮轰 Shell 的管道运算符不够语义化。会有人跟你对线。
    如果你认为 F 这个命名不够语义化可以用 Pipe,Python3 里你甚至可以给它一个中文名,管道。够语义化吗?
    Jirajine
        16
    Jirajine  
       2021-01-10 19:51:20 +08:00 via Android
    @abersheeran 复制粘贴是可以,但每个模块都复制粘贴一遍也不合适,还是得自己建一个模块再倒入,这和直接从 pypi 导入也没多大区别吧?
    再者一般情况都从 pypi 找包,即使让人直接从 readme 里复制粘贴。不上的话不利于曝光需要的人也很难找到。
    YUX
        17
    YUX  
       2021-01-10 20:07:10 +08:00
    `range(10) | F(filter, lambda x: x % 2) | F(sum)` 是奇数和叭
    dorafmon
        18
    dorafmon  
       2021-01-10 20:54:25 +08:00
    @Jirajine 用这个呗, 不是很接近了? https://pypi.org/project/pipetools/
    abersheeran
        19
    abersheeran  
    OP
       2021-01-10 21:08:25 +08:00 via Android
    @YUX 谢谢指正,写错了哈哈哈。好尴尬,待会就改。
    aijam
        20
    aijam  
       2021-01-10 21:12:58 +08:00
    abersheeran
        21
    abersheeran  
    OP
       2021-01-10 21:15:38 +08:00 via Android
    @Jirajine 有道理。待会就发一个。
    abersheeran
        22
    abersheeran  
    OP
       2021-01-10 21:24:08 +08:00 via Android
    @aijam 各有各的好。我这个一共只有六行代码,工作原理简单,对 Python 原本用法几乎无改变,可以和现在的代码混合使用,使用成本低、收益高。
    你给的那个库,需要从数据源头包一层,返回的也是个它的自定义对象,没办法做到随意的混合使用。当然,它那个只需要在源头和结尾申明一下,可以少输入几个字符,这方面还是有优势的。
    fpure
        23
    fpure  
       2021-01-11 00:18:19 +08:00 via Android
    不错,很优雅的代码
    alan0liang
        24
    alan0liang  
       2021-01-11 08:18:57 +08:00 via Android
    想到了 ECMAScript 的 proposal pipeline op: https://github.com/tc39/proposal-pipeline-operator
    大概长这样:
    64 |> Math.sqrt |> (x => x + 1) |> console.log
    或者:
    64 |> Math.sqrt |> # + 1 |> console.log
    frostming
        25
    frostming  
       2021-01-11 08:42:12 +08:00
    我记得很久之前哪里看到过,类似小技巧一类的文章
    不过你这个可以柯里化一下更好:
    range(10) | F(filter)(lambda x: x % 2) | F(sum)
    frostming
        26
    frostming  
       2021-01-11 08:42:44 +08:00
    这样我可以:
    Filter = F(filter)
    Sum = F(sum)
    abersheeran
        27
    abersheeran  
    OP
       2021-01-11 09:13:31 +08:00
    @frostming 嗯? F 从 partial 继承而来,本就可以绑定参数的。😀
    Ritter
        28
    Ritter  
       2021-01-11 09:37:54 +08:00
    一直以为 partial 是个函数 原来是个类。。。
    zone10
        29
    zone10  
       2021-01-11 10:10:51 +08:00
    我之前看过一个函数式的库, 也很有意思.我现在有个思路是用更高效的语言来实现这个,不知道能不能保证 Python 便利性的同时提高性能
    abersheeran
        30
    abersheeran  
    OP
       2021-01-11 10:13:38 +08:00
    @zone10 partial 本身就是 C 写的,虽然在标准库里也有一个 C 模块不可用时的 Pure Python 降级代替,但编译正常的 CPython 都会用那个 C 版本。所以这里的性能损耗几乎不可能更低了。
    abersheeran
        31
    abersheeran  
    OP
       2021-01-11 10:17:22 +08:00
    @Ritter 一般这种类似于一个函数功能的类,都会以小写命名,而不是死板的遵守 pep8 。
    SjwNo1
        32
    SjwNo1  
       2021-01-11 10:27:15 +08:00
    还有其他类似的实现吗,学习了
    Wincer
        33
    Wincer  
       2021-01-11 10:34:20 +08:00
    不错👍,不过 python 要是能在所有 function 共同的父类(说法不太准确?)上面定义 __ror__ 就好了,这样应该就可以实现:range(10) | filter(lambda x: x%2) 的写法,更接近于函数式编程语言的管道了。
    dinjufen
        34
    dinjufen  
       2021-01-11 10:58:16 +08:00
    666,花哨的东西学不来
    frostming
        35
    frostming  
       2021-01-11 10:59:29 +08:00
    @Wincer C 实现的类要加额外方法要动用 ctypes
    我很久前写了个黑魔法
    https://github.com/frostming/gorella
    wellsc
        36
    wellsc  
       2021-01-11 11:01:49 +08:00
    666 这个好神奇
    NeezerGu
        37
    NeezerGu  
       2021-01-11 11:09:10 +08:00
    @abersheeran 路过,昨天看这个学习了一阵,partial 是 python 代码实现的吧?
    abersheeran
        38
    abersheeran  
    OP
       2021-01-11 11:18:59 +08:00
    @NeezerGu 自己看标准库源码吧。搜这一行 from _functools import partial
    bruce00
        39
    bruce00  
       2021-01-11 11:34:58 +08:00
    楼主博客好看~
    Wincer
        40
    Wincer  
       2021-01-11 11:37:54 +08:00
    @frostming 沿用了你的代码,成功给 built-in 的 object 加上了 __ror__ 方法,但是还是行不通:range(10) | filter(lambda x: x % 2) 这个表达式被解释器会默认先求两端的值,如果不先求值的话,需要用 partial 包起来,不过这样又和楼主的实现差不多了。
    abersheeran
        41
    abersheeran  
    OP
       2021-01-11 11:41:18 +08:00 via Android
    @bruce00 谢谢~
    abersheeran
        42
    abersheeran  
    OP
       2021-01-11 11:44:28 +08:00 via Android
    @Wincer 要实现你这个,首先要让这些 callable 支持自动柯里化……不是支持一个管道运算符就行了的

    自动柯里化的工作量就太大了,因为 Py 里存在 *args 和 **kwargs 。我是想不到有什么好办法能实现的。所以我选择让程序员自己柯里化一次(也就是使用 F 包裹一次)。
    Wincer
        43
    Wincer  
       2021-01-11 11:46:59 +08:00
    @abersheeran 嗯是的,这确实是目前比较合适的方法了
    iqxd
        44
    iqxd  
       2021-01-11 11:48:01 +08:00
    请问下楼主 if isinstance(other, tuple): return self(*other) 是为了处理哪种情况呢?
    abersheeran
        45
    abersheeran  
    OP
       2021-01-11 11:53:13 +08:00 via Android
    @frostming
    @Wincer

    就比如说明希想要的那个,可以用
    def fp(func):
    def _(*args, **kwargs):
    return F(func, *args, **kwargs)
    return _

    折中实现一下,强制 double call 才能实际调用。

    而你要做的这个,既要支持 direct call 又要支持
    double call……那就得第一次调用之后延迟计算,判断如果是走管道,调第二次,判断直接赋值的话再去计算。CPython 应该做不到,可以考虑做个超集语言,在编译期做。
    NeezerGu
        46
    NeezerGu  
       2021-01-11 12:03:31 +08:00
    @abersheeran
    不是这个吗? https://github.com/python/cpython/blob/master/Lib/functools.py
    哦,这是说, 同时提供了 python 版本和 c 版本? 如果 c 版本的导入失败就用 python 的?
    frostming
        47
    frostming  
       2021-01-11 12:38:10 +08:00
    @Wincer 如果只是 patch function 大可直接把 builtin 的 map, filter 换掉,我说的那种可以用来给 list 加 chaining call:

    [1, 2, 3].map(lambda x: x**2)
    mckelvin
        48
    mckelvin  
       2021-01-11 13:01:55 +08:00
    `sum(i for i in range(10) if i % 2)` 比 `range(10) | F(filter, lambda x: x % 2) | F(sum)` 更难读吗?
    yuruizhe
        49
    yuruizhe  
       2021-01-11 13:04:14 +08:00 via iPhone
    @Leigg 同+1,我还纳闷 shell 咋能调用 python 函数呢…老实说,我还真没把 python shell 当成过主力 shell,都是 bash…
    muzuiget
        50
    muzuiget  
       2021-01-11 13:10:53 +08:00
    这种用法容易走火入魔。
    Merlini
        51
    Merlini  
       2021-01-11 13:14:02 +08:00
    之前做文本处理的时候看到网上一个 pipeline 写法感觉也挺不错。
    ```python
    def pipeline(
    value: T,
    function_pipeline: Sequence[Callable[[T], T]],
    ) -> T:
    """A generic Unix-like pipeline
    :param value: the value you want to pass through a pipeline
    :param function_pipeline: an ordered list of functions that
    comprise your pipeline
    """
    return reduce(lambda v, f: f(v), function_pipeline, value)
    ```
    zouzou0208
        52
    zouzou0208  
       2021-01-11 13:25:22 +08:00
    好玩,原来是 index.py 的作者。好棒。
    chaleaoch
        53
    chaleaoch  
       2021-01-11 13:29:09 +08:00
    在这么玩, 会被玩坏的喂~~~~~
    shyling
        54
    shyling  
       2021-01-11 13:43:09 +08:00
    🤪f#自带语法
    Wincer
        55
    Wincer  
       2021-01-11 14:23:56 +08:00
    @frostming 是的,这样也可以,但是适用性会窄一些,需要预先针对某一种类型 patch
    shyrock
        56
    shyrock  
       2021-01-11 14:42:38 +08:00
    赞!学习了。
    aldslvda
        57
    aldslvda  
       2021-01-11 14:52:48 +08:00
    学习了
    iintothewind
        58
    iintothewind  
       2021-01-11 16:07:57 +08:00
    你这个管道实现是不是可以再优化一下,
    毕竟每次都得带 F() 包住后面的操作符, 这个看起来有点多余。
    admirez
        59
    admirez  
       2021-01-11 16:11:52 +08:00
    pandas 也可以这样搞么?
    sapocaly
        60
    sapocaly  
       2021-01-11 16:50:00 +08:00
    个人觉得 chain funciton call 可能更符合 python 一些至少更接近 django 一些。比如 range(10).filter(lambda x: x % 2).sum()。毕竟每次加个 F 还是有点难受。当然,去掉 F 容易,我是没想到怎么实现 range(10) | filter, lambada x:x |sum 这样的 syntax
    frostming
        61
    frostming  
       2021-01-11 17:19:37 +08:00
    @sapocaly 只能魔改 builtins 了,参考我上面的回答
    sapocaly
        62
    sapocaly  
       2021-01-11 17:46:39 +08:00
    @frostming 不 我发现我之前的纠结没有意义, 如果只是要实现 range(10) | (filter, lambada x:x) |sum 或 range(10).filter(lambda x: x % 2).sum()这样的话,你只需开头用一个自己定一个 class,前者(pipe)照规矩 override ror 就行了,后者 chaining 的话我想用 metaclass 应该不难,不知道有没有更简单的。我觉得这种已经很 hack 了,改 buildin 就太过分了,没必要也不合适。当然如果你非要实现 range(10) | filter(lambada x:x) |sum 这样的,确实可能只能 patch 了,当然我会建议 patch a limited scope 而不是 explicitly override
    sapocaly
        63
    sapocaly  
       2021-01-11 17:52:14 +08:00
    补充一下,比较容易实现的 chain 的用法会是 Chain.range(10).filter(lambda x:x % 2).sum().end(),稍微难一点的是 Chain.range(10).filter(lambda x:x % 2).sum(),我猜这里我得想下类似 lazy eval 的实现。如果想直接 range(10).filter(lambda x:x % 2).sum(),我可能会用 with patched_buildin(): range(10).filter(lambda x:x % 2).sum()这样的 syntax 当然讨厌 indentation 的话自然也有别的办法
    sapocaly
        64
    sapocaly  
       2021-01-11 17:54:13 +08:00
    想了想似乎 metaclass 都不需要
    abersheeran
        65
    abersheeran  
    OP
       2021-01-11 18:03:21 +08:00 via Android
    @NeezerGu 对的。

    @admirez 可以,此管道可以用在任何 Python 代码里。我就是在处理数据的时候想到的这个。

    @sapocaly 你说的这个不就是楼上推荐的那个库吗?你喜欢的话可以去试试,上面有链接。我个人喜欢 | F(...) 这么用。没有黑魔法,工作原理简单,对 debug 友好,最重要的优点是每一次管道运算都是真实的运算出了结果,我可以在任何一次运算之后拿去用,而不需要特意标识一个 END 或者其他什么的。
    xuboying
        66
    xuboying  
       2021-01-11 18:04:45 +08:00
    楼主不去写 perl6 可惜了,python 的名人名言是只能有一种写法,不遵守人的可以去开发其他语言(逃)
    Tumblr
        67
    Tumblr  
       2021-01-11 18:07:05 +08:00
    啊!这很 PowerShell !很 pwsh !
    abersheeran
        68
    abersheeran  
    OP
       2021-01-11 18:10:13 +08:00 via Android
    @mckelvin 我文章里解释过了。管道的数据处理顺序跟阅读顺序是一样的。利于阅读代码。
    你说的这个嵌套用法当然可以,可是阅读顺序和实际的执行顺序是相反的,它先执行的内部函数再执行的外部函数。
    NeezerGu
        69
    NeezerGu  
       2021-01-11 18:12:21 +08:00
    @abersheeran 原来如此,感谢哈。
    sapocaly
        70
    sapocaly  
       2021-01-11 18:15:46 +08:00
    @abersheeran 额其实我很久没写 python 了,倒不是真要用到,不过觉得你提出的这个问题挺有意思所以想想有啥别的实现。我看了那个库介绍,和我理想中的比较接近,我觉得 END 是可以去掉的,但当然这又要加很多 hack 。 至于哪种 syntax 我比较喜欢,我觉得都还行,不过我觉得我现实中不会去用。简单的逻辑没必要,复杂的逻辑 chain 或者 pipe 的可读性并不会增加,也大概率效率不是最好的。当然,我也很久没用 python 了,效率这个还得具体问题具体分析。
    xuboying
        71
    xuboying  
       2021-01-11 18:31:51 +08:00
    为何要特殊处理 tuple,没有 get 到 OP 的意图,有什么特殊情况可以简便写法么?
    >>> (1, 2 , 3) | F(filter, lambda x: x % 2) | F(list)
    TypeError: filter expected 2 arguments, got 4

    >>> [1, 2 , 3] | F(filter, lambda x: x % 2) | F(list)
    [1, 3]

    >>> list(filter( lambda x: x % 2,(1,2,3)))
    [1, 3]
    abersheeran
        72
    abersheeran  
    OP
       2021-01-11 19:20:39 +08:00
    @sapocaly 嗯,关于此的讨论你可以看看楼上我、 @frostming 和 @Wincer 发的。更好、更简单的实现方法目前来看,在 CPython 里是没有的。如果自己实现一个 Python 超集的编译器,那就可以做到了。

    @iqxd @xuboying 因为我希望能传递多个参数给被 F 包裹的函数。一般来说,函数返回多值是 return x, y, z 这样,它的实际类型是一个 tuple 。

    比如

    def fa(...): return a, b, c
    def fb(a, b, c, d, e): return y

    就可以直接 data | F(fa) | F(fb), 而不是 data | F(fa) | F(lambda args: F(fb(*args))) 这样写。
    maddevil
        73
    maddevil  
       2021-01-11 19:24:49 +08:00
    from functools import partial

    F = type("F", (partial,), {"__ror__": lambda self, other: self(other)})
    range(10) | F(filter, lambda x: x & 1) | F(sum) | F(print)
    geebos
        74
    geebos  
       2021-01-11 19:44:23 +08:00
    个人觉得可以写成装饰器

    ```python
    from functools import partial

    class F(partial):
    def __init__(self, func):
    self.__func = func

    def __ror__(self, other):
    if isinstance(other, tuple):
    return self(*other)
    return self(other)

    def __call__(self, *args, **kwargs):
    return self.__func(*args, **kwargs)

    def pipefy(func):
    return F(func)

    ```
    zyb201314
        75
    zyb201314  
       2021-01-11 21:07:19 +08:00 via Android
    这就是牛人技术探讨吗?作为小白的我完全参入不进讨论, 只能给你们鼓掌.
    crclz
        76
    crclz  
       2021-01-11 21:09:30 +08:00
    可以可以,脚本语言就应该有脚本的样子
    24bit
        77
    24bit  
       2021-01-11 23:35:01 +08:00
    赞一个
    lithbitren
        78
    lithbitren  
       2021-01-12 01:29:41 +08:00
    非常有意思
    AlexChing
        79
    AlexChing  
       2021-01-12 09:59:30 +08:00
    这个在 python 的数据预处理阶段确实是很实用的。数据预处理需要按照特定的流程来走,自己一个个的写流程确实很难受。
    Reficul
        80
    Reficul  
       2021-01-12 10:12:33 +08:00
    差点真被唬住了, 原来是覆盖了位运算的或。。。

    秒啊~
    xuboying
        81
    xuboying  
       2021-01-12 10:56:15 +08:00
    @abersheeran #72 感谢 OP 提供了一个非常好的思路,用在 notebook 里做数据分析非常实用,写项目估计会被大多数 team 打死。。。
    ror 差点被骗了,以为是循环,看了一下文档以后我想再重载一个运算符,这样就不用粗暴的使用 tuple 来判断处理逻辑了,代码如下:

    $ cat foo.py
    from functools import partial


    class F(partial):
    def __ror__(self, rhs):
    return self(rhs)

    def __rrshift__(self, rhs):
    return self(*rhs)


    $ python -i foo.py
    >>> (1, 2 , 3) | F(filter, lambda x: x % 2) | F(list)
    [1, 3]
    >>> (14, '#b') >> F(format)
    '0b1110'
    >>>
    xuboying
        82
    xuboying  
       2021-01-12 11:05:00 +08:00
    @xuboying #81 草率了。。ror 和 rrshift 有优先级关系,一起用不方便。。。
    abersheeran
        83
    abersheeran  
    OP
       2021-01-12 11:37:40 +08:00
    @xuboying 哈哈,如果你想要拆分成两个字符,不妨考虑 `|` 和 `^` 这两没有优先级问题。
    Leviathann
        84
    Leviathann  
       2021-01-12 12:51:52 +08:00 via iPhone
    @alan0liang 这个 sharp 让我想到了 Mathematica
    no1xsyzy
        85
    no1xsyzy  
       2021-01-12 13:25:00 +08:00
    @abersheeran | ^ 这两个也有优先级问题, ^ 优先级高
    似乎 | 没有同优先级的……

    @geebos 你的 __init__ 和 __call__ 的功能已经被 partial 实现了……
    abersheeran
        86
    abersheeran  
    OP
       2021-01-12 13:34:53 +08:00
    no1xsyzy
        87
    no1xsyzy  
       2021-01-12 13:48:22 +08:00
    最长的管道实现:发 PEP 要求增加 |> 和 ||> 操作符
    no1xsyzy
        88
    no1xsyzy  
       2021-01-12 14:01:06 +08:00
    @abersheeran 再想了下,可能比较歪
    a / F(b) :: b(a)
    a // F(b) :: b(*a)
    a @ F(b) :: map(b, a)
    a % F(b) :: filter(b, a)
    a * F(b) :: reduce(b, a)
    abersheeran
        89
    abersheeran  
    OP
       2021-01-12 15:06:55 +08:00
    @no1xsyzy 提这个 PEP,Guido 会回复:I don't like it. Closed. 哈哈哈
    woostundy
        90
    woostundy  
       2021-01-12 15:30:06 +08:00
    或运算有时候还挺常用的。
    要是能自己增加运算符以及定义就好了。
    no1xsyzy
        91
    no1xsyzy  
       2021-01-12 15:32:04 +08:00
    @abersheeran 大人,时代变了
    Guido 不是也不喜欢 := 么……
    abersheeran
        92
    abersheeran  
    OP
       2021-01-12 15:36:34 +08:00
    @no1xsyzy 但是能和他对着干的,也就那么几个大佬吧。红姐提交模式匹配的 PR 不还是 Guido 直接 Closed 嘛。
    xuboying
        93
    xuboying  
       2021-01-12 16:10:20 +08:00
    @no1xsyzy #85 @abersheeran
    花了点摸鱼的时间略微改造了一个符合我个人喜好的版本,以后做数据分析手指就轻松了。

    我发现 partial 的类很特殊,不能简单继承,或者前面有人提到了 Filter=F(filter)似乎也是不行的。

    希望有高人能帮忙简化一下我的写法。

    ···
    $ cat foo.py
    from functools import partial


    class P(partial):
    """Pipe."""

    def __ror__(self, rhs):
    return self(rhs)


    class X(partial):
    """Xargs."""

    def __ror__(self, rhs):
    return self(*rhs)


    class Filter(P):

    def __new__(cls, *args, **kwargs):
    return super(__class__, cls).__new__(cls, filter, *args, **kwargs)


    class Map(P):

    def __new__(cls, *args, **kwargs):
    return super(__class__, cls).__new__(cls, map, *args, **kwargs)


    $ python -i foo.py
    >>> (1, 2 , 3) | Map(lambda x : x+2 ) | Filter(lambda x: x % 2) | X(divmod) | P (set)
    {0, 3}
    ···
    abersheeran
        94
    abersheeran  
    OP
       2021-01-12 16:35:30 +08:00
    @xuboying https://github.com/abersheeran/only-pipe/discussions 方便的话可以发到这,留作记录。

    😀你这个也不错。可以再加一个 Reduce 的,就齐活了哈哈哈。
    Macv1994
        95
    Macv1994  
       2021-01-12 17:11:58 +08:00
    想问一下题主,怎么样才能像你一样写出这样优雅的代码,可以说一下学习路线吗?
    abersheeran
        96
    abersheeran  
    OP
       2021-01-12 17:23:05 +08:00
    @Macv1994 学习路线?额……你可以看看我博客,按时间顺序倒着看。那个差不多就能展示我的学习路线了。
    yueyoum
        97
    yueyoum  
       2021-01-12 18:48:26 +08:00
    我为了 回复此贴, 特意登陆了一下

    总结: 哗众取宠,毫无意义


    我已经 抛弃 python 了


    工业应用,各种炫技代码,不是 平铺直述 的代码, 我全部都是 review 不通过的

    如果一个 语言 写了 4 年 还能从 语法上玩出花样, 或者 一个语言 写了 4 年 还没掌握全部的语言特性
    ( c++除外, 特定领域 和 高性能 是别人的卖点)

    那么 在这种语言上 浪费时间是 毫无意义的


    什么是好语言:

    1. 语法 几天 学完
    2. 语言特性 几个月 完全掌握
    3. 有强力的 IDE 支持
    4. 强类型,编译检查错误
    5. 如果运行效率高最好
    6. 如果容易的支持并行最好

    python 一样都没占上

    连最基本的 语言特性, 我敢说 这个帖子里 没有一个人 完全掌握了 python 的特性


    所以, 自己玩玩可以
    abersheeran
        98
    abersheeran  
    OP
       2021-01-12 18:55:32 +08:00
    @yueyoum 喔。你是 Golang 的粉丝吧。
    lizytalk
        99
    lizytalk  
       2021-01-12 19:10:46 +08:00
    @aijam #20 我觉得这里面的 pipe 的设计比楼主的好
    xuboying
        100
    xuboying  
       2021-01-12 19:52:20 +08:00 via Android
    @yueyoum 从语法的角度 op 的代码并不符合社区规范,但可能很多人(包括我)是把 op 的设计当成一个最终产品来用的,比如数据分析。op 更像是一个优秀的产品经理而不是单纯的 coder 。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5697 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 06:44 · PVG 14:44 · LAX 22:44 · JFK 01:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.