Python’s list type (part 2) — List iteration and mutability
In part 2, we will learn about
- Iterating through a list using a for loop
- Mutable vs. immutable data types
Interate a list with a for loop
We use a for
loop to iterate through the elements of a list (for
loop will be discussed in detail in the control flows article)
# First, initiate a list
x = [1, 2, 3, 4, 5]
print(x)[1, 2, 3, 4, 5]
Now, iterate through each element and print out its squares.
for e in x:
print(e**2)1
4
9
16
25
Here is what happened under the hood
- In the first iteration,
e
was assigned the first element ofx
. Thus,print(e**2)
printed out1
. - Python noticed that it had not reached the end of the list, so it move to the next iteration. This time,
e
was assigned the second element ofx
, which was2
. Thus,print(e**2)
printed out4
. - The logic happened again and again until Python finished the fifth iteration. This time, it noticed that it already reached the end of the list, and the loop ended.
Notes on indentation
Notice the indentation in the above example. print(e**2)
is indented in (indented to the right) one TAB. This indentation indicate that the indented block of code lie inside (not parallel to) the for
loop. Thus, it will be executed in each iteration.
Consider the two following examples.
# Ex 1
for e in x:
squared = e**2
print(squared)1
4
9
16
25# Ex 2
for e in x:
squared = e**2
print(squared)25
In Ex 1, both the assignment and print statement are executed 5 times (in 5 iterations).
However, in Ex 2, only the assignment is executed 5 times (because it is inside the loop). The print statement is only excuted after the loop is done. And squared
takes the value 25
from the last iteration, you see 25
printed out.
Notes on temporary variables
You should think of e
as an temporary variable to get access to each element of the list x
. Thus, you can use whatever name you want such as i
, j
, element
.
However, remember to use the same name in the statements within the for
loop. Consider the following example.
for i in x:
print(e**2)25
25
25
25
25
Here, Python iterated through all five elements of x
, and in each iteration, i
is indeed take the value of the corresponding element of x
. However, you mistakenly use e**2
not i**2
inside print()
. And from the last example, when the loop finished, e
assumed the last value of x
, which was 5
. That's why in this example, you see 25
was printed out five times.
Now, change e
inside print()
to i
and you will see everything works correctly.
for i in x:
print(i**2)1
4
9
16
25
Some more examples with for loops
Let’s do some more examples with lists using for
loops.
Ex 1: print out the following text
1 squared = 1
2 squared = 4
...
10 squared = 100x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for e in x:
print(f"{e} squared = {e**2}")1 squared = 1
2 squared = 4
3 squared = 9
4 squared = 16
5 squared = 25
6 squared = 36
7 squared = 49
8 squared = 64
9 squared = 81
10 squared = 100
Example 2:
Create a list x = [1, 2, -7, 8, -9, -4, 10, 30]
and then
- Print out only positive values of
x
- Print out only even values of
x
- Print out only positive and even values of
x
# Intiate a list
x = [1, 2, -7, 8, -9, -4, 10, 30]
print(x)[1, 2, -7, 8, -9, -4, 10, 30]
a) Print out positive values
- We loop through each element of
x
- At each iteration, check if the element is greater than 0
- If yes (
True
), print the element - If no (
False
), do nothing
for e in x:
if e > 0:
print(e)1
2
8
10
30
b) Print out even values
- We loop through each element of
x
- At each iteration, check if the element is divisible by
2
- If yes (
True
), print the element - If no (
False
), do nothing
for e in x:
if e % 2 == 0:
print(e)2
8
-4
10
30
c) Print out only positive and even values
- Combine condition in a) and b) using
and
for e in x:
if (e > 0) and (e % 2 == 0):
print(e)2
8
10
30
Example 3: Count the number of students who passed from the list of scores [1, 2, 7, 9, 10, 10, 3, 4, 8]
(assume that passing mean score >=4
)
# Initialize scores list
scores = [1, 2, 7, 9, 10, 10, 3, 4, 8]
# Initialize the number of students who passed
num_passed = 0
for s in scores:
if s >= 4:
# If we find a pass
# then increase num_passed by 1
num_passed = num_passed + 1
# After the loop is done,
# let's check how many passes we have counted
print(num_passed)6
Mutability
Lists are called mutable, meaning that we can change (mutate) its elements after it is created. The opposite of mutable is immutable, and all the flat types we have learned so far are immutable.
Many misunderstand that because we can first assign x
to an integer and after that assign x
to a different integer, then x
is mutable. That's not true.
Mutability is a characteristic of an object, not of a variable. Variable is just a name, nothing more. It has no type. When we called type(x)
, we actually get the type of the underlying object that x
is pointing to.
Let’s confirm this.
x = 5
id(x)2010989816240x = 10
id(x)2010989816400
As you can see, in the second assignment, a new object is created (different ID) to hold value 10
. Python does not reuse the object in the first assignment to hold the new value in the second assignment (If you are still confused about this, go back and read the article "Variables and assignment").
But this doesn’t make an integer immutable. In fact, if we replicate the example above with lists, we get the same results.
x = [1, 2, 3]
id(x)2011077771456x = [4, 5, 6]
id(x)2011077841024
You see, two different objects are created to hold two lists.
What makes a list mutable is that we can change its element without destroying the object (meaning the box stays the same, while its content changes)
# Create a list
x = [1, 2, 3]
id(x)2011077796736# Now append new element to it
x.append(99)# You can see the content has changed
print(x)[1, 2, 3, 99]# But the box stays the same
id(x)2011077796736
That’s what make a list mutable. For flat types, there is no mechanism like the .append()
method (more on this later) of the list type. So there's no way we can modify the value inside the object.