Python中的Clojure样式函数“threading”

时间:2011-02-10 18:17:54

标签: python functional-programming clojure

Clojure有一个“ - >” macro,以递归方式插入每个表达式作为下一个表达式的第一个参数。

这意味着我可以写:

(-> arg f1 f2 f3)

它的行为类似于(shell管道):

f3(f2(f1(arg)))

我想在Python中这样做;然而,搜索似乎是一场噩梦!我无法搜索“ - >”,也无法搜索Python函数线程

有没有办法超载,比如说,|运算符,以便我可以用Python写这个?

arg | f1 | f2 | f3

谢谢!

9 个答案:

答案 0 :(得分:18)

或者可以通过以下方式使用reduce函数:

reduce(lambda x,f : f(x), [f1,f2,f3], arg)

答案 1 :(得分:14)

你可以自己轻松实现这样的事情。

def compose(current_value, *args):
    for func in args:
        current_value = func(current_value)
    return current_value

def double(n):
    return 2*n

print compose(5, double, double) # prints 20

答案 2 :(得分:9)

或试试http://dev-tricks.net/pipe-infix-syntax-for-python 提供如下语法的模块:

  fib() | take_while(lambda x: x < 1000000)
        | where(lambda x: x % 2)
        | select(lambda x: x * x)
        | sum()

答案 3 :(得分:8)

以霍华德的解决方案为基础:

def T(*args):
  return reduce(lambda l, r: r(l), args)

def dbl(n):
    return 2*n

T(5,dbl,dbl)
#=> 20

T(5,dbl,dbl,lambda x: 3*x)
#=> 60

答案 4 :(得分:3)

虽然我同情创建酷炫的新语言结构(Lisp宏)的愿望,但实际上并不是Python哲学:

>>> import this
[...]
There should be one-- and preferably only one --obvious way to do it.

但正如受访者所说,你可以通过各种方式进行功能链接。如果适合你的想法,这可能是更明确的类似Lisp的那个:

a = lambda x: x*2
b = lambda x: x+1

def chain(first, *args):
    if len(args) == 0:
        return first
    else:
        return first(chain(*args))

print chain(b, a, 1)

答案 5 :(得分:1)

pytoolz库中有一个thread function(实际上有两个;它们在多个参数的函数上略有不同)。

还有一个名为cytoolz的pytoolz库的cython实现,它可能更有效。它可以使用pip安装。

答案 6 :(得分:1)

参加派对有点晚了,但这里有一个更干净的方法,imo。适合大多数FP需求。

def stream(*args):
    return reduce(lambda a, t: t[0](t[1], a), args[1:], args[0])

基本地图,过滤,缩小:

>>> my_list = [1, 2, 3, 4, 5]
>>> stream(my_list, 
...    (map,    lambda x: x ** 2),
...    (filter, lambda x: x < 20),
...    (reduce, lambda a, x: a + x))
30

答案 7 :(得分:1)

我相信一个非常“Pythonic”的方法是线程化这样的函数:

thread_functions(my_arg)(func1, func2, ...)

或者,如果您有多个初始参数:

thread_functions(arg1, arg2, ...)(func1, func2, ...)

要实现上述内容,可以这样做:

def thread_functions(*init_args):
    def execute_functions(*functions_list):
        x = functions_list[0](*init_args)

        for func in functions_list[1:]:
            try:
                x = func(*x)
            except TypeError:
                x = func(x)

        return x

return execute_functions

函数 thread_functions 接收初始参数集(可以是多个)并返回函数 execute_functions。调用时,execute_functions 接收一组要迭代的函数,将前一次迭代的结果应用为当前函数的参数。它还处理可迭代和不可迭代的参数。

this GitHub Gist 中,我留下了一些其他解释并实现了一些示例以更好地演示用例。

答案 8 :(得分:-2)

不,没有(至少是理智的)。你也不想。为什么不写f3(f2(f1(arg)))?或者更好的是,以不需要递归的方式对问题进行建模。

你可以通过在一个类中包装表达式并在该类中定义|来重载__or__,但是,为了对Guido的爱,请不要这样做。

您也可以执行btilly所写的内容,但我也不建议这样做。在语言为您提供的内容中工作。