Clojure 风格的函数“线程”在Python中

发布于 10-17 00:31 字数 366 浏览 4 评论 0原文

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

这意味着我可以写:

(-> arg f1 f2 f3)

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

f3(f2(f1(arg)))

我想在 Python 中执行此操作;然而,搜索似乎是一场噩梦!我无法搜索“->”,也无法搜索 Python 函数线程

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

arg | f1 | f2 | f3

谢谢!

Clojure has a "->" macro which inserts each expression recursively as the first argument of the next expression.

This means that I could write:

(-> arg f1 f2 f3)

and it behaves like (shell piping):

f3(f2(f1(arg)))

I would like to do this in Python; however, searching seems to be a nightmare! I couldn't search for "->", and neither could I search for Python function threading!

Is there a way to overload, say, the | operator so that I could write this in Python?

arg | f1 | f2 | f3

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

瑾兮2024-10-24 00:31:17

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

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

Or possibly use the reduce function in the following way:

reduce(lambda x,f : f(x), [f1,f2,f3], arg)
深白境迁sunset2024-10-24 00:31:17

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

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

You can easily implement something like this yourself.

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
云朵有点甜2024-10-24 00:31:17

或者尝试 https://mdk.fr/blog/pipe-in​​fix-语法-for-python.html
提供如下语法的模块:

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

Or try https://mdk.fr/blog/pipe-infix-syntax-for-python.html
A module that provide a syntax like :

  fib() | take_while(lambda x: x < 1000000)
        | where(lambda x: x % 2)
        | select(lambda x: x * x)
        | sum()
浮云落日2024-10-24 00:31:17

基于霍华德的解决方案:

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

Building on Howard's solution:

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
云之铃。2024-10-24 00:31:17

虽然我同情创建很酷的新语言结构(类似于 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)

While I sympathize with the desire to create cool new language constructs (à la Lisp macros), it is not really the Python philosophy to do this:

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

But as the respondents have said, you can do your function chaining in a variety of ways. Here is one that's perhaps more explicitly Lisp-like, if that suits your fancy:

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)
极度宠爱2024-10-24 00:31:17

聚会有点晚了,但我认为这是一个更干净的方法。适合大多数 FP 需求。

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

一个基本的map、filter、reduce:

>>> 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

A little late to the party, but here's a cleaner method, imo. Will suit most FP needs.

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

A basic map, filter, reduce:

>>> 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
一片旧的回忆2024-10-24 00:31:17

pytoolz库中有一个线程函数(实际上有是两个;它们对多个参数的函数执行的操作略有不同)。

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

There's a thread function in the pytoolz library (actually there are two; they do slightly different things on functions of multiple arguments).

There's also a cython implementation of the pytoolz library called cytoolz which is probably more efficient. It can be installed using pip.

养猫人2024-10-24 00:31:17

我相信一种相当“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 接收一组要迭代的函数,将上一次迭代的结果应用为当前函数的参数。它还处理可迭代和不可迭代的参数。

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

I believe that a quite "Pythonic" approach to this would be to thread functions like this:

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

Or, if you have multiple initial arguments:

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

To implement the above, one could do:

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

The function thread_functions receives the initial set of arguments (that can be many) and returns the function execute_functions. When called, execute_functions receives a set of functions to iterate on, appling the result of the previous iteration as the arguments to the current function. It also handles both iterable and non iterable arguments.

In this GitHub Gist I left some other explanations and implemented some examples to better demonstrate the use cases.

只怪假的太真实2024-10-24 00:31:17

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

您也许可以通过将表达式包装在类中并在该类中定义 __or__ 来重载 |,但出于对 Guido 的热爱,请不要这样做。

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

No, there is not (at least sanely). Nor would you want to. Why not just write f3(f2(f1(arg)))? Or better yet, model your problem in a way that doesn't require recursion.

You might be able to overload | by wrapping expressions in a class and defining __or__ in that class, but please, for the love of Guido, don't do that.

You could also do what btilly wrote, but I wouldn't recommend that either. Work within what the language provides you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文