10

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

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

baz(bar(foo(x)))) 

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

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

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

(-> x foo bar baz) . 

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

+2

Хотя оператор перегрузки поведение интересно, мне это только кажется, как плохая вещь, чтобы сделать в реальном коде. –

+0

Невозможно сделать точный синтаксис в Python, если это то, о чем вы просите. Вы можете аппроксимировать его различными способами. Что именно важно для вас синтаксически? – BrenBarn

+0

Сохранение потока слева направо.В настоящее время аргумент сложенной функции заканчивается. Было бы яснее, если бы я мог написать F() >> x >> foo >> bar >> baz или подобное. –

ответ

9

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

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

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

1

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

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

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

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

0

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

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

Это, кажется, работает для простого ввода. Не уверен, что это стоит усилий для сложного ввода, например, ((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