5

I came across a pretty clever little function that takes two functions, applies one on top of each other given an argument x:

def compose(f,g):
    return lambda *x: f(g(*x))

Now my issue is with *x, as I don't see it really doing anything here. Why couldn't it be simple x (without the asterisk)?

Here are my tests:

>>> def compose(f,g):
...   return lambda *x: f(g(*x))
... 
>>> this = lambda i: i+1
>>> that = lambda b: b+1
>>> compose(this,that)(2)
4

>>> def compose(f,g):
...   return lambda x: f(g(x))
... 
>>> compose(this,that)(2)
4

>>> def compose(f,g):
...   return lambda *x: f(g(*x))
... 
>>> compose(this,that)(2,2)
TypeError: <lambda>() takes exactly 1 argument (2 given)
ApathyBear
  • 9,057
  • 14
  • 56
  • 90

3 Answers3

5

If g (that in your tests) can also take a variable number of arguments, then lambda *x: f(g(*x)) can be useful.

Otherwise, not so much.

The aim is to allow the composed function to be invoked with any number of arguments, and for all these arguments to be passed to the inner function in the composition.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
3

To complement @Frederic's answer, it would be most flexible if compose used the standard *args, **kwargs construct:

def compose(f,g):
   return lambda *args, **kwargs: f(g(*args, **kwargs))

This way, compose works with any g function, regardless of g's signature.

The one in your question is only using the first part, i.e. the *args, and using a different (unconventional) name for it, *x.

Community
  • 1
  • 1
shx2
  • 61,779
  • 13
  • 130
  • 153
1

The problem with your tests is that your composition functions this and that only accept a single argument, so the point of the * in your compose function is lost (and you receive a "takes exactly 1 argument " error).

The power of the * operator becomes apparent when you want to pass in unpacked tuples, and your lambdas support this:

Try this simple map reduce example:

this = lambda *i: *[x**2 for x in i]  # map tuple i
that = lambda *b: sum(b) # reduce tuple b

def compose(f,g):
    return lambda *x: f(*g(*x))

compose(that,this)(2,2)
Martin Konecny
  • 57,827
  • 19
  • 139
  • 159