Подтвердить что ты не робот

Clojure функция стиля "threading" в Python

Clojure имеет макрос "- > ", который рекурсивно вставляет каждое выражение в качестве первого аргумента следующего выражения.

Это означает, что я мог бы написать:

(-> arg f1 f2 f3)

и он ведет себя как (оболочка):

f3(f2(f1(arg)))

Я хотел бы сделать это в Python; однако поиск кажется кошмаром! Я не мог найти "- > ", и я не мог искать потоки функций Python!

Есть ли способ перегрузить, скажем, | оператора, чтобы я мог написать это в Python?

arg | f1 | f2 | f3

Спасибо!

4b9b3361

Ответ 1

Вы можете легко реализовать что-то подобное себе.

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

Или, возможно, используйте функцию уменьшения следующим образом:

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

Ответ 3

Или попробуйте https://mdk.fr/blog/pipe-infix-syntax-for-python.html Модуль, обеспечивающий такой синтаксис:

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

Ответ 4

Основываясь на решении Говарда:

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

Ответ 5

Пока я сочувствую желанию создавать классные новые языковые конструкции (макросы à la Lisp), на самом деле это не философия Python:

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

Но, как сказали респонденты, вы можете выполнять цепочки функций различными способами. Вот, возможно, более явно Lisp -like, если это соответствует вашей фантазии:

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)

Ответ 6

Немного поздно на вечеринку, но здесь более чистый метод, имо. Подойдет большинство потребностей 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

В библиотеке pytoolz есть функция потока (на самом деле их две, они немного отличаются друг от друга по функциям из нескольких аргументов).

Там также реализована реализация cython библиотеки pytoolz под названием cytoolz, которая, вероятно, более эффективна. Его можно установить с помощью pip.

Ответ 8

Нет, нет (по крайней мере, здраво). И вы бы этого не хотели. Почему бы просто написать f3(f2(f1(arg)))? Или еще лучше, смоделируйте свою проблему таким образом, чтобы не требовать рекурсии.

Возможно, вы сможете перегрузить |, обернув выражения в классе и определяя __or__ в этом классе, но, пожалуйста, для любви к Гвидо, не делайте этого.

Вы также можете сделать то, что написал btilly, но я бы тоже не рекомендовал это делать. Работайте над тем, что дает вам язык.