请参阅toolz.thread_first()
和toolz.thread_last()
。
在我看来,他们使代码严格恶化。考虑
x = f(x)
x = g(x)
x = h(x)
VS
x = thread_last(x,
f,
g,
h)
第一个例子是
即使你想通过x
传递一个具有x = thread_first(x, *funcs)
的可变大小的函数列表,这也可以通过常规迭代来完成 - 这又是更详细的,但是,不管怎么说,这种情况并不常见。
为什么有人想要使用thread_first()
和thread_last()
?它对我来说基本上看起来非常糟糕。 原则上,实现一种通过函数管道参数列表的方法可以通过并行化实现加速 - 但在我看来并不像在这些实现中实际发生这种情况。
答案 0 :(得分:2)
虽然这主要是基于意见,但有许多好处:
命名很难(或者他们说)thread_*
或pipe
允许您跳过中间分配。无需发明数十个中间名称,甚至更糟糕的是生活在x
,y
,z
个变量中。
专注于数据流和数据结构启用干净的声明式样式。代码的大部分可以表示为简单的数据结构,并使用标准数据结构方法进行转换。可以说,它使您的代码更容易理解:
thread_first(
url,
requests.get,
requests.models.Response.json,
operator.itemgetter("result"))
并撰写/重用代码:
request_pipeline = [authorize, fetch, validate]
api_response = [render_json]
html_response = [render_html]
thread_first(request, *request_pipeline + api_response)
thread_first(request, *request_pipeline + html_response)
将焦点转移到引用透明度它自然地强制执行小的,引用透明的函数,并且作为副作用(双关语)使您的代码更容易调试。
它可以很好地处理延迟代码(toolz.map
,toolz.filter
),这使得它可以用于数据处理,可能是无限的数据结构。
最后你必须记住,这些功能不是单独存在的。它们旨在与toolz
的其他部分(尤其是函数组合和currying),内置模块(如operator
)一起使用,并且与第三方工具(如multipledispatch
一起玩得非常好) )。只有这样,他们才能充分发挥自己的力量。
然而 toolz
中实现的许多想法在严格的函数式语言(Clojure和Elixir)中更为自然,正如您所提到的,对于Python开发人员来说可能并不自然。