1

Lets say we have functions in python:

def _abs(iterable):   #cause its normally for one element only
    return [abs(i) for i in iterable]

def A(list, foo):
    return foo(list)

list = [2,3,-5]
print( A(list,foo=sum) )

>> 0

while I may pass foo=sum to A, I am looking for an elegant way to pass something like foo=sum(_abs) to perform sum(_abs(list)).

The only way I see it now is to send a list of functions [sum, _abs] and apply them in order. Is there a better way?

Martijn Pieters
  • 963,270
  • 265
  • 3,804
  • 3,187
Yurkee
  • 735
  • 2
  • 7
  • 23
  • Are you asking about function *composition* (rather than nesting) http://stackoverflow.com/questions/16739290/composing-functions-in-python – doctorlove Dec 18 '16 at 12:21
  • 4
    What you are describing is *"function composition"*. If you want to do this kind of functional-style programming, consider using a library dedicated to the purpose: http://toolz.readthedocs.io/en/latest/api.html?highlight=compos#toolz.functoolz.compose. Or just try `foo=lambda l: sum(map(abs, l))`. – jonrsharpe Dec 18 '16 at 12:22
  • 2
    As a side note, it's usually recommend to return a generator instead of a list, for your `_abs` it would be: `return (abs(i) for in iterable)` – Markus Meskanen Dec 18 '16 at 12:32
  • @jonrsharpe that's an excellent solution, and exactly what I've been looking for. MarkusMeskanen why is so? – Yurkee Dec 18 '16 at 12:39
  • @MarkusMeskanen or `map(abs, iterable)` if they're using 3.x. – jonrsharpe Dec 18 '16 at 12:40

3 Answers3

6

Or, to compose more generally (i.e. with an arbitrary number of argument functions):

from functools import partial, reduce

def compose(*funcs):
    return partial(reduce, lambda x, f: f(x), reversed(funcs))

(see the docs on partial and reduce - note you don't need to import reduce in Python 2.x)

Then:

>>> compose(sum, _abs)([2, 3, -5])
10
jonrsharpe
  • 107,083
  • 22
  • 201
  • 376
4

You could make an explicit compose function

>>> def compose(f, g):
...   return lambda x: f(g(x))
...

Then use it

>>> A(list, compose(sum, _abs))
10
doctorlove
  • 18,125
  • 2
  • 46
  • 59
2
def compose(funcs, funcargs):
    for func in reversed(funcs):
        funcargs = func(funcargs)
    return funcargs
smilingwang
  • 109
  • 6