3.1. Readings#

3.1.1. Algorithms and pseudocode#

Before we sit down and write code to solve a problem, it is important to have a plan on how to solve it. This series of steps that will solve the problem is called an algorithm.

Algorithms can be expressed in pseudocode or flowcharts before being actually written. Pseudocode is writing code but in normal, spoken language. On the other hand a flowchart is a graphical representation of the flow of control (order of steps) of an algorithm.

Let us look at an example. Suppose we want to see if a number is positive or negative. Fig. 3.1 below shows an example of an algorithm’s pseudocode and flowchart.

flowchart_pseudocode_illustration

Fig. 3.1 Pseudocode and Flowchart Example#

Here is the program that corresponds with the flowchart and pseudocode above.

x = -5
if x > 0:
    print('Positive number')
if x < 0:
    print('Negative number')
Negative number

3.1.2. Conditional statements#

Conditional statements are used to decide which part of the code should be executed based on whether a specific condition is fulfilled or not.

3.1.2.1. if statements#

The syntax for the one-way conditional statement is:

if condition:
    do something

The code inside the if block will be executed only if the condition in the if statement evaluates to True. Let us look at some examples.

x = 5
if x > 0:
    print('x is positive')
x is positive

Since the condition of the if statement evaluates to True, the print statement is going to be executed and we see the printed result.

if x < 0:
    print('x is negative')

As expected, the above code cell does not display anything because the condition x > 0 evaluates to False, thus the code block inside the if statement does not execute.

3.1.2.2. if-else statements#

if-else statements are also known as two-way conditional or selection statements. The syntax of the if-else statement is as follows:

if condition:
    do something
else:
    do another thing

The control flow is: if the condition in the if statement is True, then the block inside the if statement is going to get executed. If the condition fails, then the block in the else statement will be executed.

To better understand this, let us look at some examples.

points = 100
if points >= 85:
    print('Congratulations! You passed the level.')
else:
    print('Try again.')
Congratulations! You passed the level.

In this case, we are assigning the value 100 to the points variable. The condition in the if statement evaluates to True, so the print statement inside the if block is going to be executed. The block in the else statement is completely ignored and the execution would continue with whatever comes after the if-else block.

is_rainning = False
if is_rainning:
    print('Take an umbrella with you.')
else:
    print('No need for an umbrella today.')
No need for an umbrella today.

In the above code snippet, is_rainning is set to False. This means that the condition in the if statement will be False so whatever is in the else block will be executed. Thus, in this case we see the string in the else block printed out.

3.1.2.3. if-elif-else statements#

What happens if there are multiple conditions to check? Clearly the one-way and two-way selection statements are not enough. For this, the if-elif-else statements are useful. The syntax of the if-elif-else statements is:

if condition_1:
    do action_1
elif condition_2:
    do action_2
else:
    do action_3

We can chain as many conditions as we want in elif blocks, however the starting block is an if block and the end block is an else block to account for default cases.

Let us see some examples below. We want to model the grading scale of ETH to the descriptions for each grade.

grade = 5
if grade>=5.75 and grade<=6.0:
    print('Excellent')
elif grade>=5.25 and grade<=5.5:
    print('Very Good')
elif grade>=4.75 and grade<=5.0:
    print('Good')
elif grade>=4.25 and grade<=4.5:
    print('Satisfactory')
elif grade==4.0:
    print('Sufficient')
else:
    print('Insufficient')
Good

In this case, each condition will be evaluated from the beginning of the code snippet until the end. The first condition to be checked will be the one in the if statement. If that evaluates to True, Excellent will be printed and the other statements skipped. If the condition fails, then the second one is checked. The same logic is used until either a condition evaluates to True or the else statement is reached.

It is not mandatory to include an else statement in the end. However, there will not be any action taken if all previous conditions have failed.

grade = 3
if grade>=5.75 and grade<=6.0:
    print('Excellent')
elif grade>=5.25 and grade<=5.5:
    print('Very Good')
elif grade>=4.75 and grade<=5.0:
    print('Good')
elif grade>=4.25 and grade<=4.5:
    print('Satisfactory')
elif grade==4.0:
    print('Sufficient')
elif grade>6.0 or grade<1:
    print('Wrong grade')

In this case, nothing is printed because no condition evaluates to True when grade = 3.

Note

It is also possible to nest if blocks inside an if, else or elif blocks. An example would be the following code snippet:

grade = 5
if grade>=5.25:
    if grade>=5.75: # grade is already greater than 5.25, is it greater than 5.75 too?
        print('Excellent')
    else: # grade greater than 5.25 but less than 5.75
        print('Very Good')
else: # grade less than 5.25
    print('Good or Satisfactory')
Good or Satisfactory

Warning

It is important to pay attention to indentation in Python. Adding unnecessary indentation will lead to IndentationError. Indentation should be consistent inside code blocks. See the below code for an example of a situation that will cause this error.

grade = 5
if grade>=5.25:
     if grade>=5.75: # added extra space at the beginning of this line
         print('Excellent')
    else: 
        print('Very Good')
 else: # adding extra space at the beginning of this line
    print('Good or Satisfactory')

3.1.2.4. Ternary operator#

The ternary operator offers a short-hand notation for an if-else statement. Its structure is:

variable_name = value_1 if condition is True else value_2

The variable_name will be assigned value_1 if the condition is True, otherwise it will be assigned the value_2. An example would be:

number = 5
value = 'odd' if number%2==1 else 'even'
print('Number', number, 'is', value)
Number 5 is odd

Thinking of the previous example in the if-else section, it would be transformed to:

is_rainning = True
print('Take an umbrella with you.' if is_rainning else 'No need for an umbrella today.')
Take an umbrella with you.

3.1.3. Loops#

Sometimes some parts of code need to run repeatedly as long as a condition is true. In these cases, it can be impossible (or at least extremely inefficient) to write sequential code to accomplish this because this would end up in a pile of copy-pasted statements that are very difficult to read and maintain. This is where loops are handy. Python has two built-in loop structures: while and for loops. Below we will see both of them in action.

3.1.3.1. while loop#

The structure of a while loop is:

while (condition is true):
    do something

The while loop will run the block inside for as many times as the condition (shown in the brackets () above) is true. Let us see a classic example.

i = 5
while i > 0:
    print('i =', i)
    i = i - 1
i = 5
i = 4
i = 3
i = 2
i = 1

As you can see, the above loop will repeat the block

    print('i = ', i)
    i = i - 1

until the condition i > 0 will be true. Each time the body of the loop gets executed, the value of i is printed and the next step is to decrease the value of i by 1. This process will repeat 5 times. After 1 has been printed, i becomes 0 and the condition that i > 0 fails, thus the loop ends. i is also called the loop condition variable. Fig. 3.2 shows the flowchart for the above code snippet.

In case we do not decrease the value of i then, the loop would run forever. This is otherwise known as infinite loop. Let us examine why this would happen. Since we never change the value of i anywhere, i in each iteration will be 5. This means that the condition i > 0 will always be true and the body of the loop would run forever.

Warning

Do not forget to update the value of the loop condition variable in the body of the while loop, otherwise you might encounter an infinite loop that will never finish executing.

while_flowchart_illustration

Fig. 3.2 While Loop Flowchart#

3.1.3.2. for loop#

The for-loop has the same purpose as the while-loop but it has a different structure, which looks like this:

for variable in sequence:
    do something

Note

As you can see from the structure above, when we use a for-loop we are more protected from an infinite loop than in while-loops as it will execute only as many times as there are elements in the sequence.

The above while-loop written using a for-loop would look like this:

for i in [5,4,3,2,1]:
    print('i =', i)
i = 5
i = 4
i = 3
i = 2
i = 1

We have a list of numbers [5, 4, 3, 2, 1]. The for-loop will iterate over this list of numbers and for each of the elements will run the statement print('i = ', i). In each iteration, one of the elements of the list is assigned to the variable i, which then is printed. The loop will finish the execution once there are no more elements on the list anymore. As you can see, here we do not need to explicitly change the value of the loop continuation variable.

Just like iterating over a list of numbers we can iterate over a string as well.

for c in 'Welcome to Python Programming!':
    print(c, end='/')
W/e/l/c/o/m/e/ /t/o/ /P/y/t/h/o/n/ /P/r/o/g/r/a/m/m/i/n/g/!/

In each iteration, one of the letters of the string Welcome to Python Programming! is assigned to the loop variable c which is printed. The end argument provided to the print function defines the character that will separate c’s values when they are printed. In this case, we are using a forward-slash(/). If we do not provide anything, like in the above code snippets, then the default value of the end parameter is the newline character (\n). That is the reason why everything we have printed in the previous examples has been on a new line.

3.1.3.2.1. for-loop with an else clause#

In Python it is possible to have an else block after a for loop. In this case, the else block will have a similar function to that in the if-else statements, i.e., it will do something after all elements are exhausted. See the example below.

for i in [0,1,2]:
    print(i)
else:
    print('Loop is done')
0
1
2
Loop is done

3.1.3.3. Nested loops#

It is possible to nest a loop inside another for- or while- loop. Let us see this in action. We want to find out the best combination of a fermented food with a fermented drink. To do this, we first have to find out and print all combinations. Below you can see the list of the available fermented_foods and fermented_drinks.

fermented_foods = ['kimchi', 'sourdough', 'cheese']
fermented_drinks = ['tequila', 'mezcal', 'wine']

for food in fermented_foods:
    for drink in fermented_drinks:
        print(food, '-', drink)
kimchi - tequila
kimchi - mezcal
kimchi - wine
sourdough - tequila
sourdough - mezcal
sourdough - wine
cheese - tequila
cheese - mezcal
cheese - wine

You can see all possible combinations of foods and drinks that we had in our lists. For each food in the outer list we iterate 3 times, since there are 3 drinks in the fermented_drinks list. So in total the whole block would iterate 9 times: 3 times the outer loop for each of the foods in the fermented_foods list and for each food it iterates 3 times over the list of drinks.

Note

It is also possible to nest a for loop within a while loop or vice versa. Try this out!

i = 0
while i < 3:
    for drink in fermented_drinks:
        print(fermented_foods[i], '-', drink)
    i = i + 1
kimchi - tequila
kimchi - mezcal
kimchi - wine
sourdough - tequila
sourdough - mezcal
sourdough - wine
cheese - tequila
cheese - mezcal
cheese - wine

3.1.3.4. range() function#

The range() function is another built-in function in Python. As its name suggests, it is useful to build ranges of values. For example, if we want to iterate over the range from 0 to 5 we would write:

for i in range(0, 6):
    print(i, end=' ')
0 1 2 3 4 5 

The general syntax for the range() function is:

range(start, end, step)

The start value is inclusive while the end value is non-inclusive. That is why in the example above, we had to specify 6 as the end value. The step determines how much we should add to each value.

If we want a decreasing range, we would write:

for i in range(5, 0, -1):
    print(i, end=' ')
5 4 3 2 1 

When we provide a single argument to the range() function, the start value is assumed to be 0 by default and the end value would be the one specified.

for i in range(6):
    print(i, end=' ')
0 1 2 3 4 5 

3.1.3.5. continue and break statements in loops#

The continue statement is used to stop the current iteration of the loop and go to the next one if the condition would hold (while loop) or there would be more items to iterate over (for loop). For example:

for food in fermented_foods:
    if food == 'kimchi':
        continue
    print(food)
sourdough
cheese

What happens here is that when food is assigned kimchi from the list, the print() statement will be skipped and the food variable will be assigned the next element in the list, sourdough, which is printed. The loop continues with the rest of the values in the list. The continue statement tells the loop to ignore whatever is left in this iteration and just directly begin the next iteration.

The break statement, on the other hand, breaks the loop completely and continues executing the statements after the loop. For example:

for drink in fermented_drinks:
    if drink == 'mezcal':
        break
    print(drink)
print('all done!')
tequila
all done!

In the above case, the loop will stop immediately without executing the print() when drink is assigned the value mezcal. As you can see, since mezcal is the second element in the list, only tequila is printed, the other 2 elements are skipped since the loop terminates.

3.1.3.6. pass statement#

You must always provide a body for a loop, being it while or for. If you do not do so, you will get a SyntaxError. To circumvent this error and have a loop without a body, you can use the pass statement as below. The loop will run as many times as the condition would allow it, but it will not do anything. If you combine it with other statements in the body of the loop, then it will not have any effect. The control-flow will proceed as we have explained above.

Warning

A while-loop with a pass statement is likely to lead to an infinite-loop. This happens because we need to update the value of the loop condition variable inside the body of the while loop, which in this case is empty. Example:

i=3
while i>0:
    pass
for i in [0,1,2]:
    pass

The above code will run 3 times but each time it will do nothing.