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 管道

  •  6
     
  •   abersheeran ·
    abersheeran · 49 天前 · 9024 次点击
    这是一个创建于 49 天前的主题,其中的信息可能已经有所发展或是发生改变。

    不多说,直接上代码。

    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 条附言  ·  47 天前

    应某位回复者的要求,已经发布到 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 条附言  ·  47 天前

    有回复者提到的 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  
    no1xsyzy
        101
    no1xsyzy   47 天前
    @yueyoum 你先做个能够同时符合你这 6 条里两条的语言出来吧。
    这六条,两两冲突……
    black11black
        102
    black11black   46 天前
    震惊于还有这种写法

    看了楼上的讨论,对我个人而言感觉最合适的语法是

    ```
    a = PIPE | range(10) | (map , str) | END
    ```

    这种格式,有初始化时不需要显式新建对象,感觉有时间可以封装一下
    black11black
        103
    black11black   46 天前
    我觉得直接封装函数无意义,比如 PIPE 并不直接返回结果而是创建一个可供输入的对象,我并不常用这种功能。如果有需要我更愿意另外显式封装函数
    abersheeran
        104
    abersheeran   46 天前
    @black11black 如果是这么用呢?

    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
    black11black
        105
    black11black   46 天前
    @abersheeran 这么用的话使用上就很舒服了,但是这些 filter map 之类的是自建类吧,感觉不是那么的完美,像 LZ 这个实现,每个函数外面还要加个 F (),感觉也很不 pythonic 。我大概把我上面的想法写了一下是这样



    > i = PIPE | range(10) | (map , lambda x:x + 1) | list | set | END
    > {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    > func = lambda x: PIPE | range(x) | (map , lambda x:x + 1) | list | set | END
    > func(5)
    > {1, 2, 3, 4, 5, 6}
    SmiteChow
        106
    SmiteChow   46 天前
    管道应该面向生成器,如果不是则逻辑的实质为不同函数的流式调用,流式调用必须要有 schema 声明以及对应的解释 shema 逻辑才对的。
    SmiteChow
        107
    SmiteChow   46 天前
    所以你把管道和流式调用弄混了
    SmiteChow
        108
    SmiteChow   46 天前
    但这也能说明你的 python 功力不错,赞。
    abersheeran
        109
    abersheeran   46 天前 via Android
    @SmiteChow 我对管道的理解来自于 Shell,这里指的也是 Shell 那种管道。
    aguesuka
        110
    aguesuka   46 天前 via Android
    管道是一个优先级较低的左结合中缀运算符。(表达式 运算符 函数) 相当于 (函数 表达式)。作为中缀表达式,它的两个类型不同,不满足交换和结合律,不能保证参数 imutable 。我觉得不适合出现在常规的编程语言中。
    而且实现是右结合的,如果左边实现了 lor 应该会有问题。
    lyzh
        111
    lyzh   46 天前
    @SmiteChow 这里没问题,Filter 和 map 这类本身就可以被柯里化绑定成一个单参函数,然后由管道加入调用流
    lyzh
        112
    lyzh   46 天前
    @aguesuka 管道中不宜出现副作用,这和“管道”的定义本身就是相悖的
    SmiteChow
        113
    SmiteChow   45 天前
    @abersheeran Shell 的管道是可以多次读写的(对应过来就是生成器),你可以细心观察一下

    ```
    echo 1 ; sleep 1 ; echo 2|cat
    ```
    SmiteChow
        114
    SmiteChow   45 天前
    @lyzh 对的,你举例是将生成器的职责落到了“管道”两端的子操作上去,但这更加说明“管道”不是真正意义上的管道,仅仅是流式调用。
    yueyoum
        115
    yueyoum   45 天前
    @no1xsyzy 我并没有说 好语言 是要全部占完, 而是 python 一样都沾不上
    no1xsyzy
        116
    no1xsyzy   45 天前
    @yueyoum
    1. 你看来中文运用不是特别好。
    “什么是好语言:”然后罗列特点 123456,然后说好语言不需要全部占完…… 挺微妙的。

    2. 你看来中文理解不是特别好。
    什么叫“两两冲突”?不是说不能全部占完,你能占两样就是登天难。

    3. 我只好建议你抛弃中文了,一方面根据 1. 2. 中文对你似乎有点困难。
    二来,让我稍微改下你的原话 ——
    什么是好语言:
    123456
    中文 一样都没占上
    连最基本的 语言特性, 我敢说 这个帖子里 没有一个人 完全掌握了 中文 的特性
    所以, 自己玩玩可以

    想了想,我建议你使用拉丁语
    yueyoum
        117
    yueyoum   40 天前
    @no1xsyzy

    你自己 去小学重修语文吧

    或者看看 一句名言: better than nothing

    已经 block 了, 不用劳烦你打字回复了
    no1xsyzy
        118
    no1xsyzy   40 天前
    @yueyoum 打滚打得好,当个猪妈宝
    css3
        119
    css3   33 天前
    简介,好用,但没懂是怎么解析出来 | 这个符号的
    css3
        120
    css3   33 天前
    就是或运算符吗
    abersheeran
        121
    abersheeran   33 天前
    @css3 是的。还有更多用法讨论在 GitHub discussion 里。可以看看。
    vance123
        122
    vance123   10 天前
    @abersheeran 虽然已经是很久以前的帖子了, 不过还是挖一下坟吧.

    这样的用法我过去在 Mathematica 里见过, 有语法层面的支持, 被称作 postfix operator, 即用 x ~ f 来表示 f(x).
    在看到楼主帖子后我又搜索了一下, 发现更确切的叫法是 forward pipe operator, 在函数式语言中比较常见, 例如 F#中的`|>`.
    有人试图在 C#里引入该特性( https://github.com/dotnet/roslyn/issues/5445), 虽然没通过, 但双方对利弊展开了精彩的讨论.
    希望能对楼主和其他人有所帮助
    1  2  
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1041 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 22:16 · PVG 06:16 · LAX 14:16 · JFK 17:16
    ♥ Do have faith in what you're doing.