Skip to content
Home » Save Loop Variable’s Value in Functions Nested in Loops

Save Loop Variable’s Value in Functions Nested in Loops

Spread the love

Today we’ll be talking about saving the current value of a loop variable in functions nested in loops. Sounds more complicated than it really is.

If you prefer to watch a video first, here it is:

Closures

First of all let’s have a look at the following example:

>>> def ten_to_power(): 
...     x = 10
...     return lambda n: x ** n
... 

Here we have a function with another function nested in it. The nested function is defined using a lambda expression. What’s important here is the value of the variable x, which we defined in the outer function. This value is remembered by the function which the outer function returns. Let’s check it out.

Now a references the object returned by the outer function, which is the inner function:

>>> a = ten_to_power()  

We can now use the variable a as the inner function. Although the outer function has already exited, the value of the x variable defined in it is still retained in the inner function. So, let’s use the inner function with some arguments:

>>> a(2)
100
>>> a(3)
1000
>>> a(6)
1000000

As you can see, the function still raises 10 to the power specified by the argument.

So, the nested function remembers the value of a variable defined in the enclosing function even after it exits.

We call such functions closures or factory methods and you can read about them in more detail in this article.

Function in Loop

But now let’s get to our actual topic of this article. The question is: what if a function is in a loop, which itself is inside the enclosing function? If we create a function in each iteration of the loop, will each function remember the current value of the loop variable? Let’s check it out.

Let’s define a function with a loop and a nested function created with a lambda expression inside the loop. The outer function uses the loop to create 5 functions which are appended to the adders list and then returned from the outer function:

>>> def makeAdders(): 
...     adders = []
...     for num in range(5):
...         adders.append(lambda x: x + num)
...     return adders
... 

Let’s call the outer function and assign the list of functions it returns to adds:

>>> adds = makeAdders()

Your Panda3D Magazine

Make Awesome Games and Other 3D Apps

with Panda3D and Blender using Python.

Cool stuff, easy to follow articles.

Get the magazine here (PDF).

Now adds is a list of 5 functions. Let’s see the first element in the list:

>>> adds[0]
<function makeAdders.<locals>.<lambda> at 0x00000207E6C401E0>

As you can see it’s a function. The other 4 elements are functions too. What do the functions do? They should add the value of the current loop variable to the number passed as an argument.

So, in the first iteration of the loop the value of the loop variable was 0. So the first function should return the sum of 0 and 10. But does it?

>>> adds[0](10)
14

It turns out it doesn’t. Let’s check the other four functions:

>>> adds[1](10)
14
>>> adds[2](10)
14
>>> adds[3](10)
14
>>> adds[4](10)
14

As you can see they all return the same value. Only the last function returns what seems correct. In the last iteration the value of the loop variable was 4, hence the result 14.

Python Jumpstart Course

Learn the basics of Python, including OOP.

with lots of exercises, easy to follow

The course is available on Udemy.

Looks like all the functions created inside the loop remember the same value of the loop variable num. It’s the value from the last iteration. This is because the loop variable is looked up only when the created functions are later called and then the value of the variable is the one from the last iteration.

As we can see, with loops closures don’t work as expected. But how can we get around it? Well, we have to use default arguments. It means we have to pass the current value of the loop variable with a default. Defaults are evaluated when the functions are created and not only when they’re called. This way each function will remember the current value of the loop variable. Here’s how we can modify our code to make it work as expected:

>>> def makeAdders(): 
...     adders = []
...     for num in range(5):
...         adders.append(lambda x, num = num: x + num)
...     return adders
... 
>>> adds = makeAdders()
>>> adds[0]
<function makeAdders.<locals>.<lambda> at 0x00000207E6C40268>
>>> adds[0](10)
10
>>> adds[1](10)
11
>>> adds[2](10)
12
>>> adds[3](10)
13
>>> adds[4](10)
14

Blender Jumpstart Course

Learn the basics of 3D modeling in Blender.

step-by-step, easy to follow, visually rich

The course is available on Udemy and on Skillshare.


Spread the love

Leave a Reply