Conditional & Repetitive Statements¶
Conditional Statements¶
Every programming language provides some way of conditional execution, and Python is no exception.
Occasionally, we would like a statement to be executed only if a certain condition is met. We can do this using the if
keyword:
if 3 < 5:
print('3 is less than 5')
3 is less than 5
The syntax looks like the following:
if <boolean-expression>:
<statement-1>
...
<statement-N>
If the boolean expression is evaluated to True
, then the statements inside the if
block will be executed, and they will be ignored if the expression is not True
.
The statements inside the conditional statement should be indented (prefixed by whitespace) in order to be properly understood by the interpreter:
# This won't work
if 10 != 20:
print('10 is not equal to 20') # No indentation
File "<ipython-input-2-743042b48091>", line 3 print('10 is not equal to 20') # No indentation ^ IndentationError: expected an indented block
You can use tab characters or multiple spaces for indentation, but please be consistent in terms of what you are using.
As a classic option, using four spaces is never a bad choice for a single level of indentation.
Optionally, we can add an else
block to the if statement (with the same syntax) if we want some statements to execute if the condition is False
:
a = 5
b = 10
if a == b:
print('Equal!')
else:
print('Not equal!')
print('How could', a, 'be equal to', b, 'anyway?')
Not equal! How could 5 be equal to 10 anyway?
Here's the example we did in class, using nested if statements to decide what we will be doing today as our outdoor activity:
activity = 'nothing'
weather = 'sunny'
shoe_count = 1
if weather == 'rainy':
activity = 'movies'
else:
if shoe_count > 2:
activity = 'tennis'
else:
activity = 'yoga'
print('Activity:', activity)
Activity: yoga
elif
is shorthand for else if
, and it also lets us keep the same level of indentation without explicit nested if-else
loops:
number = 15
if number < 5:
print('less than 5')
elif number < 10:
print('num between 5 and 10')
elif number < 20:
print('num between 10 and 20')
else:
print('Num greater than 20')
num between 10 and 20
The example of representing a piecewise assignment routine, as done in class:
x = 10
if x < 1:
s = (x + 1) ** 2
elif x < 10:
s = x - 0.5
elif x < 100:
s = (x + 0.5) ** 0.5
else:
s = 0
s
3.24037034920393
The boolean expression of the if statement can use many operators, such as arithmetic, logical comparison (<
, >
, !=
, ...), logical operators (or
, not
, ...) and membership (in
, not in
).
a = 5
if a < 3 or a > 8:
print('a is not between 3 and 8')
else:
print('a in (3, 8)')
a in (3, 8)
And here's the example of finding the maximum number between three given numbers, using nested if statements (as done in class):
a = 40
b = 30
c = 20
if a > b:
if a > c:
print(a)
else:
print(c)
else: # b > a
if b > c:
print(b)
else:
print(c)
40
Repetitive Statements¶
Repetitive statements let us use the same code to do something multiple times. This is useful when, for example:
- We need to go over all of the elements in a container
- Our algorithm needs to explore every possibility in a simulation
- Our program should continue until some condition is reached.
Python provides us with for
and while
statements, and they are similar.
while
statements are like this:
while <boolean-expression>:
<statement-1>
...
<statement-N>
Similarly to if
, if the expression evaluates to True
, then the statements inside the while
block will be executed. Then, the expression will be evaluated again, and if it is True
, then the contents will be executed again (and again, again, again...). This continues until the boolean expression is False
, at which point the while
loop terminates.
Here's an example of counting to 5 using a while loop:
i = 0
while i < 5:
print('i is:', i)
i = i + 1 # Update the value of i
print('Final value', i)
i is: 0 i is: 1 i is: 2 i is: 3 i is: 4 Final value 5
i
in the example above is used as a counter, which is a variable that accumulates values inside the loop. Such variables are common in while
loops.
Here's an example of printing each character inside a string (or any type of sequential container, actually):
i = 0 # The first element has index 0
s = 'hello'
while i < len(s):
print(s[i]) # Print the element with the current index
i += 1
h e l l o
Here's an example of finding out the sum of all natural numbers from 0, up to some number:
upper_limit = 100
# We'll talk about range() very soon
l = list(range(upper_limit + 1)) # Gives [0, 1, ..., 100]
print(l)
i = 0
total = 0
while i < len(l):
total = total + l[i]
i += 1
print('Sum of the list:', total)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100] Sum of the list: 5050
range()
is a common utility for getting a sequence of numbers to use in loops.
Technically, it returns an iterator
, which you can use directly with while
/ for
.
If you want a list, you can wrap it with list()
.
for
is similar to while, and its main use is iterating over elements in a container.
The syntax is like:
for <var> in <container>:
<statement-1>
...
<statement-N>
In each iteration, the current element taken from the container is assigned to var
. Here's the same element traversal code with for
, instead of while
:
for character in 'hello':
print(character)
h e l l o
Note that we did not need to deal with keeping track of the index ourselves.
However, if you still want to have an index while using for
, you can wrap the container with the enumerate()
function. Inside a for
block, this will give the current index of the element along with the element itself, as a tuple:
for i, character in enumerate('hello'):
print(character, 'has index', i)
h has index 0 e has index 1 l has index 2 l has index 3 o has index 4
Another example of for
, using a list.
Notice that the name between for..in
does not matter if you're not using it, and you don't have to use the elements in the loop:
l = [10, '20', 5.0]
# Print hello as many times as the length of the list
for dummy in l:
print('hello')
hello hello hello
Let's use what we learned in the past two weeks: How can we find the smallest number in a list of randomly generated numbers?
Don't forget that
- The list could be empty, in which case, there would not be a smallest number.
- The list could have just one element, in which case, that element is trivially the smallest number.
Here's our implementation in class:
# How can we get the maximum number inside of a list?
# The list can have any number of elements
import random
l = []
num_elems = 10
# Generate random numbers and put them into the list
for i in range(num_elems):
l.append(random.randint(0, 100))
print('List:', l)
# Finding the smallest number
length = len(l)
if length == 0:
print('Empty list!')
elif length == 1:
print('Smallest number:', l[0])
else:
smallest = l[0]
i = 1
while i < len(l):
print('Current smallest number:', smallest)
print('Candidate number:', l[i])
if l[i] < smallest:
smallest = l[i]
i += 1
print('Smallest number:', smallest)
List: [38, 78, 14, 94, 87, 63, 53, 64, 9, 48] Current smallest number: 38 Candidate number: 78 Current smallest number: 38 Candidate number: 14 Current smallest number: 14 Candidate number: 94 Current smallest number: 14 Candidate number: 87 Current smallest number: 14 Candidate number: 63 Current smallest number: 14 Candidate number: 53 Current smallest number: 14 Candidate number: 64 Current smallest number: 14 Candidate number: 9 Current smallest number: 9 Candidate number: 48 Smallest number: 9
break
and continue
¶
These statements let us interrupt the logical flow inside of a for
or while
loop.
When we reach a break
statement, Python will immediately break out of the enclosing loop. (If you are in nested for
/ while
loops, you will break out of the inner-most loop)
The following loop will run until i == 5
, in which case it will stop, without going to 10:
i = 0
while i < 10:
print(i)
if i == 5:
break
i += 1
0 1 2 3 4 5
continue
will jump the flow of execution back to the boolean expression immediately.
In the example below, we print a string character-by-character while ignoring a specific character, using continue
:
for c in 'hello':
if c == 'l':
continue # Don't execute print(c) below, go back to the top
print(c)
h e o
If the boolean statement inside the while
loop is always True
, then the loop will never terminate. This is called an infinite loop.
This might be intentional (some programs are designed to run forever, until some external signal is given), or non-intentional (one might forget to increment the iteration variable in a loop).
Here's an example of breaking out of an infinite while
loop using the break
keyword.
while True:
num = random.randint(0, 10)
print(num)
if num == 5:
break
1 4 4 0 10 2 5
List and Set Comprehension¶
Python gives us a convenient way of generating sets and lists using something similar to the set builder syntax from mathematics:
$\{x | x \in \{0, 1, ..., 10\} \wedge x > 5\}$
[x for x in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if x > 5]
[6, 7, 8, 9, 10]
The syntax for list comprehension looks like
[<exp> for <var> in <iterable (container)> (if <condition>) ]
You use if
statements inside the list comprehension, if you want to filter out some values from appearing the list.
Here's a very simple comprehension:
[x ** 2 for x in [1,2, 3]]
[1, 4, 9]
Let's get all of the odd numbers from 0 to 100:
# If x is even, then x % 2 == 0
# If x is odd, then x % 2 == 1
[x for x in range(100) if x % 2 == 1]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]
We can put all characters inside of a string, into their own list, as follows:
[s for s in 'hello']
['h', 'e', 'l', 'l', 'o']
We can get set comprehensions, by using curly braces instead of square brackets:
{s for s in 'hello'}
{'e', 'h', 'l', 'o'}
Notice that 'l'
does not repeat in the comprehension, because set
s only contain unique elements.
You can use multiple for
values inside of a list comprehension, which acts like nested for
loops:
[(x, y) for x in [1,2] for y in [3, 4, 5]]
[(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)]
These resemble cartesian products from mathematics:
[(x, y) for x in 'hello' for y in range(5)]
[('h', 0), ('h', 1), ('h', 2), ('h', 3), ('h', 4), ('e', 0), ('e', 1), ('e', 2), ('e', 3), ('e', 4), ('l', 0), ('l', 1), ('l', 2), ('l', 3), ('l', 4), ('l', 0), ('l', 1), ('l', 2), ('l', 3), ('l', 4), ('o', 0), ('o', 1), ('o', 2), ('o', 3), ('o', 4)]
Finally, the list comprehension has access to outside variables, so the example below will also work:
s = 15
[x for x in range(20) if x < s]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]