Reputation: 13
I have this piece of code, and i am confused about it's execution:
def makeInc(x):
def inc(y):
return y + x
return inc
inc5 = makeInc(5)
# print inc5 ---> <function inc at 0xb721bdbc>
inc5(12)
# print inc5(12) gives 17
So, I am wondering why it makes the sum, x+y
, only on the second call of the function inc5()
.
I know what a closure in python really means, but I am still confused.
I have found that piece of code in this web page: http://ynniv.com/blog/2007/08/closures-in-python.html
Upvotes: 1
Views: 79
Reputation: 44092
Here are comments to what is happening.
makeInc
is a function, which returns another function. Using closures, the returned function knows
about x
being set to value as it was true at the moment it was created and returned.
Calling inc2 = makeInc(5)
first makes x
inside makeInc
set to 5, and then creates a function
y
. This inc
function knows that x
equals to 5 and will remember it as long as it lives - this is concept of closures (get in your backpack all needed variables in the environment at the moment of birth).
Calling inc5(12)
executes inc(12)
. Inside if this call to inc
it adds argument y
being 12 to the value of x
, which the inc5
remembers is 5, so the sum makes 17.
N.B.: Closures are used naturaly in languages like JavaScript. In Python, closures are available too, but not used so often and some developers are considering them even evil - your question shows very clearly, it is not trivial to understand, what is happening in the code - this goes against "readibility counts" from Zen of Python. Also you can find some surprises related to scope and visibility of variables. In case you do not get exactly what has happened in the code above, do not worry, Python offers many other nice challenging structures, which you will use much more often (list comprehension being one example).
Upvotes: 3
Reputation: 19544
The other answers explain it well, but here's a line by line breakdown of what happens in your code
def makeInc(x): # define a function makeInc that takes a variable x
# when makeInc is executed, define a function "inc" that takes a variable y
def inc(y):
# when inc is executed, return the sum (where x is closed in the outer function)
# note this is not executed when makeInc is called
return y + x
# don't call inc yet, just return a reference to the function itself - note there
# are no parenthesis after inc
return inc
inc5 = makeInc(5) # now execute makeInc which returns a reference to the inc function
# with the variable x captured by the closure
inc5(12) # now call the result of the above which is the only place that we call inc
# note the parenthesis to designate the function call
# print inc5(12) gives 17
Central to understanding this is the concept of functions as objects. In Python you can do this:
>>> def test(x):
... return x + 6
...
>>> test(1) # call test with the argument x = 1
7
>>> a = test # assign the function "test" to a new variable "a" - this is not calling test
>>> a
<function test at 0x101cfbb90> # printing a shows the original function name "test"
>>> a(1) # now call that function again with the same value for x = 1
7
When makeInc
is called, it returns a reference to inc
within which has a different function signature (taking an argument called y). The fact that they both take a single argument is not relevant.
Upvotes: 2