Loop¶
while
for
- Break and Continue
- Two Examples
while
Loop¶
This section introduces the concepts of while
statement and infinite loop.
- The Concept
- The Statement
- Infinite Loop
- Sentinel
The while
Concept¶
It it a common scenario that you repeat some actions when a certain condition is true.
- You repeatedly "learn" while a topic that puzzles you.
- The rice cooker "cooks" rice for 30 minutes.
- Your program keeps asking a user to give an input if the current input is invalid.
The following diagram shows the concept.
The while
statement¶
As depicted in the above diagram, the while
statement has a while
clause and a code block. The syntax is as the following:
while condition:
statement
statement
...
statement // after-while statement
When the condition is true, it repeatedly executes the statements in the code block. Each execution of the loop body (code block) is called an iteration. Looping is also called iterating. If the condition becomes false, it skip the code block and runs the statements below it. Below is an example:
Initial Value¶
Because the while
clause first checks a condition, the code needs to set a certain value make the condition True
. Below we set the confirmation to 'yes'
thus when Python executes the while
statement, the condition is True
and the statements in the code block are executed. When the confirmation input is not 'yes'
, it skip the code block and run the statement(s) below the while
statement.
# a program to calculate the total of user inputs
total = 0
confirmation = 'yes'
while confirmation == 'yes':
number = int(input('Please input an integer: '))
total += number # += is an abbreviation of total = total + num
confirmation = input('more numbers? yes for continue, otherwise stop.')
print(f'The total is {total}')
Infinite Loop¶
It is very important to change the condition in the code block of a while
statement. Following is a program that we want to calculate the sum from 1 to 10.
total = 0 # don't use sum as the variable name because it is a built-in function name
number = 1
while number <= 10:
total += number
print(f'The total from 1 to 10 is {total}')
If you run the above code, it never ends until the system fails to handle a big number or doesn't have enough memory. The program enters an infinite loop. The reason is the the while
clause is always evaluate to True
. To fix it, you should change the condition in the code block.
Remember to Change Condition¶
Whenever you write a while
statement, remember to change the condition inside the code block to avoid infinite loop.
sum = 0
number = 1
while (number <= 10):
sum += number
number += 1
print(f'The sum from 1 to 10 is {sum}')
Sentinel¶
The while
clause checks a boolean expression to control the iteration. If you use a variable value to represent the completion
/end
/stop
case, the value is called a sentinel. It is important that a sentinel should not be a normal input value, otherwise the program can not tell the special end value from normal values. For example, if a program asks user to input positive numbers, it can use -1
to mark the end of the while loop.
# a program to calculate the total of user inputs
total = 0
number = int(input('Please input a positive number, input -1 to stop: '))
while number != -1:
total += number # += is an abbreviation of total = total + num
number = int(input('Please input a positive number, input -1 to stop: '))
print(f'The total is {total}')
Exercise-1¶
In the above sentinel code example, the prompt message is repeated before and after while
. Please change the code to call the input
function only in one place.
Exercise-2¶
The following code runs an infinite loop, can you tell what's wrong? Try to fix it.
total = 0
confirmation = 'yes'
while confirmation == 'yes':
number = int(input('Please input an integer: '))
total += number # += is an abbreviation of sum = sum + num
confirmation2 = input('more numbers? yes for continue, otherwise stop.')
print(f'The total is {total}')
The for
Loop¶
- Concept
- Statement
- Nested loops
- Range function
- Enumerate with Index
The for
Loop Concept¶
Like the while
loop, the for
loop has two parts: a for
clause and a code block.
The for
clause gets each element from a sequence
, assigns each item to an variable and execute the code block. It completes when there is no more elements in the sequence.
The variable used in the for
clause is called a target variable
because it is assigned the value of each element in the sequence in each loop iteration. It is important to give it a meaningful variable name.
Conceptually, it works as the following flow chart:
The for
Loop Syntax¶
The syntax of for
loop is as the following:
for variable_name in sequence:
statement
statement
...
Following are two examples that print out elements in a sequence -- you use the target variable to access each element:
students = ['Alice', 'Bob', 'Cindy']
for student in students:
print(student)
print('All students are printed\n')
Nested Loop¶
In the code block of a loop statement, you can have another loop statement, this is called nested loop. Conceptually it is rather simple, just treat the nested loop as a regular statement and everything becomes clear. Following is an example. As you can see, the inner for char
loop is repeated for each number in the outer for number
loop. Practice more and you will have a better understanding.
numbers = [1, 2, 3]
chars = ["A", "B", "C"]
print('Outside loop')
for number in numbers:
print('Inside number loop')
for char in chars:
print('Inside char loop')
print(number, char)
Exercise¶
Exercise: change the following for
loop code to use while
loop.
students = ['Alice', 'Bob', 'Cindy']
for student in students:
print(student)
print('All students are printed\n')
The range
Function¶
Many time you want to repeat a block code for a number of times. Python has a built-in function range
that generates a sequence of numbers.
range(n)
generates a sequence of integers in the range of 0
up to, but not including, the number n
. For example, range(3)
generates a sequence of 0
, 1
and 2
.
for item in range(10):
print(f'Current item: {item}')
More Parameters¶
The range function can take one, two, or three arguments.
range(m, n)
: generate a sequence of integers in the range ofm
up to, but not including, the numbern
. For example,range(3, 7)
generates a sequence of3
,4
,5
, and6
.range(m, n, step)
, generate a sequence of integers in the range ofm
up to, but not including, the numbern
, the generate numbers increase at the specified step. For example,range(3, 7, 2)
generates a sequence of3
and5
.7
is not in the generated list because numbers bigger than or equal to7
are excluded.
It is possible to use a negative step in a range
function to generate a list from high to low, in a reversed order. For example, range(3, 0, -1)
generates a list of [3, 2, 1]
.
for item in range(3, 10, 2):
print(f'Current item: {item}')
The Index Idiom¶
You can compose the len
and the range
functions to generate a sequence of the index numbers for a list. For the above students list, the composed function range(len(students))
generates a sequence of 0, 1 and 2.
Actually, it is an idiom in Python to use the composed function to access both the item and its index in a list. Following is an example to display students and there places in the list. For a typical business user, the index should starts from 1, not 0.
Using f-string, you can format the output as the following:
students = ['Alice', 'Bob', 'Cindy']
for index in range(len(students)):
print(f'Index {index}, Name: {students[index]}')
The enumerate
Function¶
When you need both the index and element value when iterating over a sequence, use enumerate
function. In each iteration, it returns the current index and current value in a pair.
students = ['Bob', 'David', 'Alice']
for (index, name) in enumerate(students):
print(f'Index {index}: {name}')
Which Version is Better?¶
What's the difference? To calculate the length of a list, you need load the whole list first into memory (eager evaluation) while the enumerate
process one element of the list at a time (lazy evaluation).
Why the difference matters? In most cases, the lazy is better than the eager version because it
- starts quickly from the first element.
- requires less memory, just one element at a time.
students = ['Alice', 'Bob', 'Cindy']
for index in range(len(students)):
print(f'Index {index}, Name: {students[index]}')
for (index, name) in enumerate(students):
print(f'Index {index}, Name: {name}')
Continue and Break¶
It is common that you don't want to perform a loop thoroughly. Two common cases are:
- Skip some statements in the suite
- Stop the loop before it completes
The Continue Concepts¶
In the code block of a for
or while
loop, sometimes you want to skip the processing for certain data. For example, when you divide a number by every element in a list, you want to skip the 0
as a divisor because it crashes the program. You use the continue
statement to continue to the next iteration of the loop. The following flow chart describes the continue control flow:
continue
Statement¶
As stated above, you use continue
statement in a certain condition to skip the current iteration and run the next iteration of the loop.
dividend = 100
numbers = [3, 5, 7, 0, 9, 2]
for number in numbers:
print(f'The element is {number}')
if number == 0:
print(f'oops, zero cannot be a divisor')
continue
quotient = dividend / number
print(f'The quotient of {dividend}/{number} is {quotient: .2f}')
The Break Concept¶
In another situate, in some conditions you want to exit the loop execution. For example, you read input from a user in a loop and the user types an exit
to exit the loop. You use the break
statement to break out of the loop. The following flow chart describes the break control flow:
The break
Statement¶
Similar to the continue
statement, you check a condition that you want exit a loop, if the condition is true
, you use break
to exit the loop and jumps to the next element after the loop structure.
dividend = 100
numbers = [3, 5, 7, 0, 9, 2,]
for number in numbers:
print(f'The element is {number}')
# exits from the loop when it sees a `0`.
if number == 0:
print(f'oops, zero divisor, clean your data first')
break
quotient = dividend / number
print(f'The quotient of {dividend}/{number} is {quotient: .2f}')
print('Done')
Stop Loop with Sentinel¶
The following example stops when it the input is the sentinel value. It skips 0
to avoid division by zero error.
SENTINEL = -1
dividend = 100
prompt = f'Please input an integer, input {SENTINEL} to exit: '
number = int(input(prompt))
while number != SENTINEL:
print(f'The input number is {number}')
if number == 0:
print(f'Zero cannot be a divisor, ignored.')
number = int(input('Please input an integer, input -1 to exit: '))
continue
# now the normal logic to process the data
quotient = dividend / number
print(f'The quotient of {dividend}/{number} is {quotient: .2f}')
# must have code to change the number
number = int(input(prompt))
print('Done')
while True:
¶
The code while True:
looks weird if it is the first time you see it. It looks like an infinite loop because the condition is always true. For this clause, there must be a break
statement in the code block to exit the loop at a certain condition. The code can be revised to get an input first and check the sentinel in the while
clause. Following is a version that checks the sentinel in while
clause.
# a sentinel is a special value that marks the end.
SENTINEL = -1
dividend = 100
prompt = f'Please input an integer, input {SENTINEL} to exit: '
while True:
number = int(input(prompt))
print(f'The input number is {number}')
if number == 0:
print(f'Zero cannot be a divisor, ignored.')
continue
if number == SENTINEL:
break
# now the normal logic to process the data
quotient = dividend / number
print(f'The quotient of {dividend}/{number} is {quotient: .2f}')
print('Done')
while
Exercise¶
Exercise: write a program that prints the first 5 odd numbers from the list [3, 8, 10, 5, 7, 0, 9, 2]
.
Two Examples¶
- Factorial with
while
andfor
- Draw spiral circles
"""Calculate the factorial of a non-negative integer"""
number = int(input('Enter a positive number: '))
# calculate number! factorial
factorial = 1
# 1 * 2 * 3 ... * number
# while loop is error-prone,
# - need variable to control the loop condition explicitly
# - often has missing-by-one bug or infinite loop
# index = 2
# while index <= number:
# factorial *= index
# index += 1
# for n in range(2, number + 1):
# factorial *= n
# decremental
for n in range(number, 1, -1):
factorial *= n
print(f'{number}! is {factorial}.')
import turtle
# don't name the file a turtle.py -- it causes a name conflict error.
# Named constants
NUM_CIRCLES = 36 # Number of circles to draw
RADIUS = 100 # Radius of each circle
ANGLE = 10 # Angle to turn
ANIMATION_SPEED = 0 # Animation speed
COLORS = ["red", "green", "blue"]
t = turtle.Turtle()
t.speed(ANIMATION_SPEED)
# Draw 36 circles, with the turtle tilted
# by 10 degrees after each circle is drawn.
color_index = 0
for x in range(NUM_CIRCLES):
t.pencolor(COLORS[color_index])
t.circle(RADIUS)
t.left(ANGLE)
color_index += 1
if color_index >= len(COLORS):
color_index = 0
t.screen.mainloop()