Лучшая функция в Python

Я работаю на Python. Недавно я обнаружил замечательный маленький пакет под названием fn. Я использовал его для создания функции.

Например, вместо:

baz(bar(foo(x))))

с fn, вы можете написать:

(F() >> foo >> bar >> baz)(x) .

Когда я увидел это, я сразу подумал о Clojure:

(-> x foo bar baz) .

Но обратите внимание, как в Clojure вход находится слева. Интересно, возможно ли это в python/fn.

Ответ 1

Вы не можете реплицировать точный синтаксис, но вы можете сделать что-то подобное:

def f(*args):
    result = args[0]

    for func in args[1:]:
        result = func(result)

    return result

Кажется, работает:

>>> f('a test', reversed, sorted, ''.join)
' aestt'

Ответ 2

Вы не можете получить точный синтаксис, хотя вы можете получить что-то вроде F(x)(foo, bar, baz). Вот простой пример:

class F(object):
    def __init__(self, arg):
        self.arg = arg

    def __call__(self, *funcs):
        arg = self.arg
        for f in funcs:
            arg = f(arg)
        return arg

def a(x):
    return x+2
def b(x):
    return x**2
def c(x):
    return 3*x

>>> F(2)(a, b, c)
48
>>> F(2)(c, b, a)
38

Это немного отличается от ответа Blender, поскольку он хранит аргумент, который впоследствии может быть повторно использован с различными функциями.

Это похоже на противоположное нормальному приложению: вместо указания функции перед фронтом и оставления некоторых аргументов, которые будут указаны позже, вы указываете аргумент и оставляете функцию (функции) указанной позже. Это интересная игрушка, но трудно подумать, почему вы действительно этого хотите.

Ответ 3

Если вы хотите использовать fn, с небольшим взломом вы можете немного приблизиться к синтаксису Clojure:

>>> def r(x): return lambda: x
>>> (F() >> r(x) >> foo >> bar >> baz)()

Посмотрите, как я добавил еще одну функцию в начале цепочки композиций, которая будет возвращать x при вызове. Проблема заключается в том, что вам все равно придется называть вашу скомпонованную функцию просто без каких-либо аргументов.

Я думаю, что ответ @Blender - ваш лучший выбор, пытающийся эмулировать функцию потока Clojure в Python.

Ответ 4

Я придумал этот

def _composition(arg, *funcs_and_args):
    """
    _composition(
        [1,2,3], 
        (filter, lambda x: x % 2 == 1), 
        (map, lambda x: x+3)
    )
    #=> [4, 6]
    """
    for func_and_args in funcs_and_args:
        func, *b = func_and_args
        arg = func(*b, arg)
    return(arg)

Ответ 5

Это, похоже, работает для простого ввода. Не уверен, что это стоит усилий для сложного ввода, например, ((42, 'spam'), {'spam': 42}).

def compose(function, *functions):
    return function if not functions else \
            lambda *args, **kwargs: function(compose(*functions)(*args, **kwargs))

def rcompose(*functions):
    return compose(*reversed(functions))

def postfix(arg, *functions):
    return rcompose(*functions)(arg)

Пример:

>>> postfix(1, str, len, hex)
'0x1'
>>> postfix(1, hex, len)
3