我正在学习一些函数式编程并查看toolz。 compose,pipe,thread_first和thread_last之间的差异对我来说似乎非常微妙或根本不存在。这些功能的预期不同用例是什么?
答案 0 :(得分:6)
compose
与thread_*
和pipe
compose
基本上是function compostion(∘)。它的主要目标是将不同的功能组合到可重用块中。与参数的顺序相比,应用程序的顺序是相反的,因此compose(f, g, h)(x)
为f(g(h(x)))
(与(f∘g)(x)相同的是 f(g(x) ))。
thread_*
和pipe
是关于使用可重用块来创建单个数据流。只能使用延迟操作来执行执行,但是块是固定的。申请顺序与参数顺序相同,因此pipe(x, f, g, h)
为h(g(f(x)))
。
compose
vs thread_*
。
compose
不允许其他参数,而thread_*
则允许。没有currying compose
只能用于一元函数。
与thread_
相比,可以使用更高级别的函数,包括常用的高阶函数:
thread_last(
range(10),
(map, lambda x: x + 1),
(filter, lambda x: x % 2 == 0)
)
与compose
相同的事情,你需要讨论:
pipe(
range(10),
lambda xs: map(lambda x: x + 1, xs),
lambda xs: filter(lambda x: x % 2 == 0, xs)
)
或
from toolz import curried
pipe(
range(10),
curried.map(lambda x: x + 1),
curried.filter(lambda x: x % 2 == 0)
)
thread_first
与thread_last
。
thread_first
将管道参数放在函数的第一个位置。
thread_last
将管道参数放在函数的最后位置。
例如
>>> from operator import pow
>>> thread_last(3, (pow, 2)) # pow(2, 3)
8
>>> thread_first(3, (pow, 2)) # pow(3, 2)
9
在实践中(忽略一些形式主义)这些功能通常是可以互换的,特别是当与functools.partial
/ toolz.curry
和一些lambda
表达式结合使用时,但根据上下文,它只是更多方便一个人使用另一个。
例如,对于内置的高阶函数,例如map
或functools.reduce
,thread_last
是一种自然选择。如果要在多个位置重用一段代码,最好使用compose(h, g, f)
而不是添加函数包装器def fgh(x) pipe(x, f, g, h)
。等等。