一个支持类似于使用 Unix 管道的函数组合的库。
项目描述
pipetools启用类似于使用 Unix 管道的功能组合。
它允许任意函数的前向组合和管道 - 无需装饰它们或做任何额外的事情。
它还打包了一堆实用程序,使常用操作更加方便和可读。
来源在github 上。
为什么?
管道和功能组合是用于大量编程任务的一些最自然的操作。然而 Python 并没有内置的方式来执行它们。这迫使您要么对函数调用进行深度嵌套,要么添加额外的胶水代码。
例子
假设您想在给定目录中创建一个 python 文件列表,按文件名长度排序,作为一个字符串,每个文件在一行上,还带有行号:
>>> print(pyfiles_by_length('../pipetools'))
1. ds_builder.py
2. __init__.py
3. compat.py
4. utils.py
5. main.py
所有的原料都已经在那里了,你只需要把它们粘在一起。你可以这样写:
def pyfiles_by_length(directory):
all_files = os.listdir(directory)
py_files = [f for f in all_files if f.endswith('.py')]
sorted_files = sorted(py_files, key=len, reverse=True)
numbered = enumerate(py_files, 1)
rows = ("{0}. {1}".format(i, f) for i, f in numbered)
return '\n'.join(rows)
或者可能是这样的:
def pyfiles_by_length(directory):
return '\n'.join('{0}. {1}'.format(*x) for x in enumerate(reversed(sorted(
[f for f in os.listdir(directory) if f.endswith('.py')], key=len)), 1))
或者,如果你是一个疯狂的科学家,你可能会这样做:
pyfiles_by_length = lambda d: (reduce('{0}\n{1}'.format,
map(lambda x: '%d. %s' % x, enumerate(reversed(sorted(
filter(lambda f: f.endswith('.py'), os.listdir(d)), key=len))))))
但应该有一种——最好只有一种——明显的方法来做到这一点。
那么是哪一个呢?好吧,为了挽回局面,pipetools给了你另一种可能!
pyfiles_by_length = (pipe
| os.listdir
| where(X.endswith('.py'))
| sort_by(len).descending
| (enumerate, X, 1)
| foreach("{0}. {1}")
| '\n'.join)
你问我为什么要这样做?与原生Python 代码相比,它是
更容易阅读——最小的额外混乱
更容易理解——从一个步骤到下一个步骤的单向数据流,没有其他需要跟踪的
更容易改变——想要更多的处理?只需在管道中添加一个步骤
消除了一些错误机会——您在第一个示例中发现错误了吗?
当然它不会解决你所有的问题,但是大量的代码可以 表示为一个管道,给你上面的好处。继续阅读以了解它是如何工作的!
安装
$ pip install pipetools
用法
管道
管道对象可用于将函数连接在一起以形成新函数,它的工作方式如下:
from pipetools import pipe
f = pipe | a | b | c
# is the same as:
def f(x):
return c(b(a(x)))
一个真实的例子,从 0 到x的奇数之和:
from functools import partial
from pipetools import pipe
odd_sum = pipe | range | partial(filter, lambda x: x % 2) | sum
odd_sum(10) # -> 25
请注意,直到总和的链是惰性的。
管道中的自动局部应用
由于部分应用在管道在一起时通常很有用,当管道遇到元组时它会自动完成,因此这会产生与前面的示例相同的结果:
odd_sum = pipe | range | (filter, lambda x: x % 2) | sum
从0.1.9开始,这更加强大,请参阅X-partial。
内置工具
Pipetools 包含一组解决一些常见任务的管道工具。例如,我们的示例中有一个过滤器类的快捷方式,称为 where():
from pipetools import pipe, where
odd_sum = pipe | range | where(lambda x: x % 2) | sum
好吧,这可能更具可读性,但并不是真正的巨大改进,但等等!
如果pipe-util用作管道中的第一项或第二项(这种情况经常发生),则可以省略开头的管道:
odd_sum = range | where(lambda x: x % 2) | sum
请参阅pipe-utils 的文档。
好的,但是丑陋的 lambda 呢?
where(),还有foreach(), sort_by()和其他管道工具都非常有用,但需要一个函数作为参数,它可以是一个命名函数——如果它做一些复杂的事情就可以——但通常这很简单,所以使用lambda是合适的。除了 Python 的 lambdas 对于简单的任务来说非常冗长而且代码变得混乱......
X对象来救援!
from pipetools import where, X
odd_sum = range | where(X % 2) | sum
那怎么办。
自动字符串格式化
由于用字符串组合函数没有意义,因此当管道(或 pipe-util)遇到字符串时,它会尝试将其用于 (高级)格式化:
>>> countdown = pipe | (range, 1) | reversed | foreach('{}...') | ' '.join | '{} boom'
>>> countdown(5)
'4... 3... 2... 1... boom'
给水管
有时创建一次性管道并立即通过它运行一些输入很有用。而且由于这有点尴尬(并且不是很可读,尤其是当管道跨越多行时):
result = (pipe | foo | bar | boo)(some_input)
也可以使用>运算符来完成:
result = some_input > pipe | foo | bar | boo
但是等等,还有更多
查看完整文档 中的 Maybe 管道、类固醇的部分应用 或自动数据结构创建。