1

In one of the training parts of my course I was given the following question:

Write a function make_multiplier(factor) that returns a function which takes an argument x and which should return factor * x.

For example:

f=make_multiplier(10)
f(1)
10
f(2)
20

I have absolutely no idea where to start with this one; I have scrummaged through all my notes and cant find anything useful.

Could someone please give me a hint or point me in the right direction of what I need to do?

5 Answers 5

4

Here is a function that returns a function:

def foo():
    def bar():
        return 42

    return bar

You can call it like so:

foo()() # 42
# or
baz = foo()
baz() # 42

There's your hint.

Sign up to request clarification or add additional context in comments.

2 Comments

aah perfect that gets it to work, I am a little confused though as to what python is actually doing when i do this, how does it understand the variable i put in at the stage "f(2)" has to be used in the indented function???
When you call f() you are calling the "indented function" - because you're calling the function that was returned.
3

Dead simple, just nest your functions:

def make_multiplier(x):
    def multiplier(y):
        return x * y
    return multiplier

Nested functions automatically look up unknown variables (x in this case) from their surrounding scope, using the value of x as it was when the outer function was called. The thing to remember here is that functions are just objects too, you can store them in a variable just like you can with other python objects, and defer calling them.

This gives:

>>> def make_multiplier(x):
...     def multiplier(y):
...         return x * y
...     return multiplier
... 
>>> f = make_multiplier(10)
>>> f(1)
10
>>> f(2)
20
>>> g = make_multiplier(5)
>>> g(1)
5
>>> f(3)
30

Note how g was given a different value for x, which is independent from the value for x in f.

You could use a lambda as well; lambdas are just anonymous functions limited to one expression; that's enough here:

def make_multiplier(x):
    return lambda y: x * y

Another alternative technique is binding x to a keyword parameter, which means you could override it if you so wish:

def make_multiplier(x):
    def multiply(y, x=x):
         return x * y
    return multiply

or the lambda version:

def make_multiplier(x):
    return lambda y, x=x: x * y

and then pass in one or two arguments to the returned callable:

>>> f = make_multiplier(10)
>>> f(5)
50
>>> f(5, 3)
15

5 Comments

Hint != giving away the answer.
You can also use the lambda syntax to simplify this case.
@Will: lambda is just semantics, and then you have to explain the difference too. Nesting a function is simpler.
@MartijnPieters you are right. It is just syntax. These simple cases are the ones where you can take advantage of it most though.
@Will: There, lambdas and a keyword argument version too.
0

In addition to Matt Ball or Martijn Pieters closure methods (which is the right answer in this particular case) there are two other forms that you will see that are worth recognizing in Python.

The first is using a lambda anonymous function:

>>> f=lambda x: x*10
>>> f(1)
10
>>> f(2)
20

The second is writing a class:

class Multiplyby:
    def __init__(self,x):
        self.x=x

    def __call__(self,y):
        return self.x*y

fx10=Multiplyby(10)
fx5=Multiplyby(5)


for y in [1,2,3]:
    print y, fx10(y), fx5(y)

prints:

1 10 5
2 20 10
3 30 15

Comments

0

Using lambdas:

>>> make_multiplier = lambda n: lambda x: x * n
>>> make_multiplier(10)(5)
50

10000000 loops, best of 3: 0.189 usec per loop

Using stdlib:

import functools
import operator

f = lambda n: functools.partial(operator.mul, n)

10000000 loops, best of 3: 0.148 usec per loop

Comments

0

I'm not recommending this, I'm just showing what's possible in point-lessfree style:

>>> from functools import partial
>>> from operator import mul
>>> make_multiplier = partial(partial, mul)
>>> f = make_multiplier(10)
>>> f(1)
10
>>> f(2)
20

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.