Краща композиційна функція в Python

Я працюю в Python. Нещодавно я відкрив дивовижний пакет з назвою fn . Я використовую його для складання функцій.

Наприклад, замість:

baz(bar(foo(x))))

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

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

Коли я це бачив, я відразу ж подумав про Clojure:

(-> x foo bar baz) .

Але зверніть увагу, як у Clojure введення знаходиться зліва. Цікаво, якщо це можливо в python/fn.

10
Там немає способу зробити точні синтаксичні роботи в Python, якщо це те, що ви задаєте. Можливо, ви зможете наблизити його різними способами. Що саме важливо для вас синтаксичним способом?
додано Автор BrenBarn, джерело
Хоча поведінка перевантаження оператора цікава, мені це просто здається поганою справою в реальному коді.
додано Автор Markus Unterwaditzer, джерело
Ведення потоку зліва направо. В даний час аргумент складеної функції знаходиться в кінці. Було б ясніше, якби я міг написати F() >> x >> foo >> bar >> baz або подібні.
додано Автор Charles R, джерело

6 Відповіді

Ви не можете повторювати точний синтаксис, але ви можете зробити щось подібне:

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

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

    return result

Здається працювати:

>>> f('a test', reversed, sorted, ''.join)
' aestt'
9
додано

Ви не можете отримати цей точний синтаксис, хоча ви можете отримати щось на зразок 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

Це дещо відрізняється від відповіді Блендера, оскільки зберігає аргумент, який пізніше можна використовувати з різними функціями.

Це схоже на протилежність застосунку звичайної функції: замість того, щоб вказати функцію вперед і залишити деякі аргументи, що будуть вказані пізніше, ви вкажете аргумент і залиште функції, які потрібно вказати пізніше. Це цікава іграшка, але важко думати, чому ти дійсно хочеш цього.

2
додано

Якщо ви хочете використовувати fn , з невеликим хаксом ви можете отримати трохи ближче до синтаксису Clojure:

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

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

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

1
додано

Я придумав це

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
додано

Моя функція compose , яка повертає функцію

def compose(*args):
    length = len(args)
    def _composeInner(lastResult, index):
        if ((length - 1) < index):
            return lastResult
        return _composeInner(args[index](lastResult), index + 1)

    return (lambda x: _composeInner(x, 0))

Використання:

fn = compose(
        lambda x: x * 2,
        lambda x: x + 2,
        lambda x: x + 1,
        lambda x: x/3
    )

result = fn(6) # -> 5
0
додано

Здається, це працює для простого введення. Не впевнені, що варто докласти зусиль для складного введення, наприклад, ((42, 'спам'), {'спам': 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
0
додано
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;