1

This is the python function from my pluralsight python class:

def raise_to(exp):
    def raise_to_exp(x):
        return pow(x, exp)
    return raise_to_exp

And the instructor now opens an interactive session and does the following:

  • from raise_to import raise_to
  • square = raise_to(2), and then goes on to do
  • square(5)

and that produces the result of 25. How or why pass in two distinct arguments? Now I ran a debug on this code and this is what I observed. When I do this:

def raise_to(exp):
    def raise_to_exp(x):
        return pow(x, exp)
    return raise_to_exp

square = raise_to(2)

print(square)

I get : <function raise_to.<locals>.raise_to_exp at 0x00000246D1A88700>, but if I do as the instructor

def raise_to(exp):
    def raise_to_exp(x):
        return pow(x, exp)
    return raise_to_exp

square = raise_to(2)

print(square(5))

I get 25. I would like to know how this works. I know this is referred as a python factory function but how does it work. Is the function storing the first argument for later use with the second argument passed in?

George Udosen
  • 906
  • 1
  • 13
  • 28

2 Answers2

5

raise_to_exp is a closure over the parameter exp defined by raise_to. When you call raise_to(2), you get back a function in whose body the variable exp refers to the variable in the scope where raise_to_exp was defined.

This means that square is a function where exp is bound to 2, so roughly equivalent to the definition

def square(x):
    return pow(x, 2)

Just to prove that there was no replacement of exp with the value 2, you can do a bit of digging into the function object to change the value of exp.

>>> square(5)
25
>>> square.__closure__[0].cell_contents = 3  # now square is cube!
>>> square(5)
125
chepner
  • 497,756
  • 71
  • 530
  • 681
2

def raise_to(exp):
    def raise_to_exp(x):
        return pow(x, exp)
    return raise_to_exp

I made the last statement bold. You're returning a function here. Think of it as

a=lambda x:x+1
a(1)
# 2

When you do

square=raise_to(2)

Now square refers to the function raise_to_exp because raise_to returned the raise_to_exp function. square can be used as a function here.

square(2) # with exp set as 2
# 4

cube=raise_to(3)
cube(2)
# 8