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
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Yurkee
  • 795
  • 2
  • 9
  • 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
  • 115,751
  • 26
  • 228
  • 437
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,872
  • 2
  • 46
  • 62
2
def compose(funcs, funcargs):
    for func in reversed(funcs):
        funcargs = func(funcargs)
    return funcargs
smilingwang
  • 119
  • 6