不多说,直接上代码。
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 调样式了。有兴趣的就看看,没兴趣的就复制代码去用就完事。
小小的得瑟一下,这是最近几天写的最满意、最有用的代码。妙手偶得之~
应某位回复者的要求,已经发布到 PyPi,顺便在 GitHub 建了个库,写了使用说明。https://github.com/abersheeran/only-pipe
稍微解决了一下好几个人觉得困扰的 tuple
判断。现在在库里,F 只会传一个参数,如果你想让 tuple 被拆解,应当使用 FF。是否解包,控制权交给程序员,而不是代码本身。
增加了一个功能,可以把 F
、reduce
释放到全局,就像 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
有回复者提到的 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)
102
black11black 2021-01-13 09:12:26 +08:00
震惊于还有这种写法
看了楼上的讨论,对我个人而言感觉最合适的语法是 ``` a = PIPE | range(10) | (map , str) | END ``` 这种格式,有初始化时不需要显式新建对象,感觉有时间可以封装一下 |
103
black11black 2021-01-13 09:15:25 +08:00
我觉得直接封装函数无意义,比如 PIPE 并不直接返回结果而是创建一个可供输入的对象,我并不常用这种功能。如果有需要我更愿意另外显式封装函数
|
104
abersheeran OP @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 |
105
black11black 2021-01-13 09:44:00 +08:00
@abersheeran 这么用的话使用上就很舒服了,但是这些 filter map 之类的是自建类吧,感觉不是那么的完美,像 LZ 这个实现,每个函数外面还要加个 F (),感觉也很不 pythonic 。我大概把我上面的想法写了一下是这样
https://gist.github.com/GoodManWEN/351fe48e24d61b8a62adef3e4460259e > 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} |
106
SmiteChow 2021-01-13 11:33:03 +08:00
管道应该面向生成器,如果不是则逻辑的实质为不同函数的流式调用,流式调用必须要有 schema 声明以及对应的解释 shema 逻辑才对的。
|
107
SmiteChow 2021-01-13 11:34:28 +08:00
所以你把管道和流式调用弄混了
|
108
SmiteChow 2021-01-13 11:45:35 +08:00
但这也能说明你的 python 功力不错,赞。
|
109
abersheeran OP @SmiteChow 我对管道的理解来自于 Shell,这里指的也是 Shell 那种管道。
|
110
aguesuka 2021-01-13 12:41:00 +08:00 via Android
管道是一个优先级较低的左结合中缀运算符。(表达式 运算符 函数) 相当于 (函数 表达式)。作为中缀表达式,它的两个类型不同,不满足交换和结合律,不能保证参数 imutable 。我觉得不适合出现在常规的编程语言中。
而且实现是右结合的,如果左边实现了 lor 应该会有问题。 |
113
SmiteChow 2021-01-14 10:32:48 +08:00
|
114
SmiteChow 2021-01-14 10:37:49 +08:00
@lyzh 对的,你举例是将生成器的职责落到了“管道”两端的子操作上去,但这更加说明“管道”不是真正意义上的管道,仅仅是流式调用。
|
116
no1xsyzy 2021-01-14 20:12:03 +08:00
@yueyoum
1. 你看来中文运用不是特别好。 “什么是好语言:”然后罗列特点 123456,然后说好语言不需要全部占完…… 挺微妙的。 2. 你看来中文理解不是特别好。 什么叫“两两冲突”?不是说不能全部占完,你能占两样就是登天难。 3. 我只好建议你抛弃中文了,一方面根据 1. 2. 中文对你似乎有点困难。 二来,让我稍微改下你的原话 —— 什么是好语言: 123456 中文 一样都没占上 连最基本的 语言特性, 我敢说 这个帖子里 没有一个人 完全掌握了 中文 的特性 所以, 自己玩玩可以 想了想,我建议你使用拉丁语 |
117
yueyoum 2021-01-19 12:12:54 +08:00
|
119
css3 2021-01-26 20:36:48 +08:00
简介,好用,但没懂是怎么解析出来 | 这个符号的
|
120
css3 2021-01-26 20:39:12 +08:00
就是或运算符吗
|
121
abersheeran OP @css3 是的。还有更多用法讨论在 GitHub discussion 里。可以看看。
|
122
vance123 2021-02-19 02:25:18 +08:00 1
@abersheeran 虽然已经是很久以前的帖子了, 不过还是挖一下坟吧.
这样的用法我过去在 Mathematica 里见过, 有语法层面的支持, 被称作 postfix operator, 即用 x ~ f 来表示 f(x). 在看到楼主帖子后我又搜索了一下, 发现更确切的叫法是 forward pipe operator, 在函数式语言中比较常见, 例如 F#中的`|>`. 有人试图在 C#里引入该特性( https://github.com/dotnet/roslyn/issues/5445), 虽然没通过, 但双方对利弊展开了精彩的讨论. 希望能对楼主和其他人有所帮助 |