Jupyter Snippet P4M 05

Jupyter Snippet P4M 05

All of these python notebooks are available at https://gitlab.erc.monash.edu.au/andrease/Python4Maths.git

Control Flow Statements

The key thing to note about Python’s control flow statements and program structure is that it uses indentation to mark blocks. Hence the amount of white space (space or tab characters) at the start of a line is very important. This generally helps to make code more readable but can catch out new users of python.

Conditionals

If

if some_condition:
    code block```
Only execute the code if some condition is satisfied


```python
x = 12
if x > 10:
    print("Hello")
Hello

If-else

if some_condition:
    algorithm 1
else:
    algorithm 2```

As above but if the condition is False, then execute the second algorithm


```python
x = 12
if 10 < x < 11:
    print("hello")
else:
    print("world")
world

Else if

if some_condition:  
    algorithm
elif some_condition:
    algorithm
else:
    algorithm```
    
Any number of conditions can be chained to find which part we want to execute.


```python
x = 10
y = 12
if x > y:
    print("x>y")
elif x < y:
    print("x<y")
else:
    print("x=y")
x<y

if statement inside a if statement or if-elif or if-else are called as nested if statements.

x = 10
y = 12
if x > y:
    print( "x>y")
elif x < y:
    print( "x<y")
    if x==10:
        print ("x=10")
    else:
        print ("invalid")
else:
    print ("x=y")
x<y
x=10

Loops

For

for variable in something:
    algorithm```
    
The "something" can be any of of the collections discussed previously (lists, sets, dictionaries). The variable is assigned each element from the collection in turn and the algorithm executed once with that value.
    
When looping over integers the `range()` function is useful which generates a range of integers:

* range(n) =  0, 1, ..., n-1
* range(m,n)= m, m+1, ..., n-1
* range(m,n,s)= m, m+s, m+2s, ..., m + ((n-m-1)//s) * s

In mathematical terms range `range(a,b)`$=[a,b)\subset\mathbb Z$


```python
for ch in 'abc':
    print(ch)
total = 0
for i in range(5):
    total += i
for i,j in [(1,2),(3,1)]:
    total += i**j
print("total =",total)
a
b
c
total = 14

In the above example, i iterates over the 0,1,2,3,4. Every time it takes each value and executes the algorithm inside the loop. It is also possible to iterate over a nested list illustrated below.

list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for list1 in list_of_lists:
        print(list1)
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

A use case of a nested for loop in this case would be,

list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
total=0
for list1 in list_of_lists:
    for x in list1:
        total = total+x
print(total)
45

There are many helper functions that make for loops even more powerful and easy to use. For example enumerate(), zip(), sorted(), reversed()

print("reversed: \t",end="")
for ch in reversed("abc"):
    print(ch,end=";")
print("\nenuemerated:\t",end="")
for i,ch in enumerate("abc"):
    print(i,"=",ch,end="; ")
print("\nzip'ed: ")
for a,x in zip("abc","xyz"):
    print(a,":",x)
reversed: 	c;b;a;
enuemerated:	0 = a; 1 = b; 2 = c; 
zip'ed: 
a : x
b : y
c : z

While

while some_condition:  
    algorithm```
    
Repeately execute the algorithm until the condition fails (or exit via a break statement as shown below)


```python
i = 1
while i < 3:
    print(i ** 2)
    i = i+1
print('Bye')
1
4
Bye

Break

The break keyword is used to abandon exection of a loop immediately. This statement can only be used in for and while loops.

for i in range(100):
    print(i,end="...")
    if i>=7:
        break
    print("completed.")
0...completed.
1...completed.
2...completed.
3...completed.
4...completed.
5...completed.
6...completed.
7...

Continue

The continue statement skips the remainder of a loop and starts the next iteration. Again this can only be used in a while or for loop. It is typically only used within an if statement (otherwise the remainder of the loop would never be executed).

for i in range(10):
    if i>4:
        print("Ignored",i)
        continue
    # this statement is not reach if i > 4
    print("Processed",i)
Processed 0
Processed 1
Processed 2
Processed 3
Processed 4
Ignored 5
Ignored 6
Ignored 7
Ignored 8
Ignored 9

Else statements on loops

Sometimes we want to know if a loop exited ‘normally’ or via a break statement. This can be achieved with an else: statement in a loop which only executes if there was no break

count = 0
while count < 10:
    count += 1
    if count % 2 == 0: # even number
        count += 2
        continue
    elif 5 < count < 9:
        break # abnormal exit if we get here!
    print("count =",count)
else: # while-else
    print("Normal exit with",count)
count = 1
count = 5
count = 9
Normal exit with 12

Catching exceptions

Sometimes it is desirable to deal with errors without stopping the whole program. This can be achieved using a try statement. Appart from dealing with with system errors, it also alows aborting from somewhere deep down in nested execution. It is possible to attach multiple error handlers depending on the type of the exception

try:
    code
except <Exception Type> as <variable name>:
    # deal with error of this type
except:
    # deal with any error
finally:
    # execute irrespective of whether an exception occured or not```


```python
try:
    count=0
    while True:
        while True:
            while True:
                print("Looping")
                count = count + 1
                if count > 3:
                    raise Exception("abort") # exit every loop or function
                if count > 4:
                    raise StopIteration("I'm bored") # built in exception type
except StopIteration as e:
    print("Stopped iteration:",e)
except Exception as e: # this is where we go when an exception is raised
    print("Caught exception:",e)
finally:
    print("All done")
Looping
Looping
Looping
Looping
Caught exception: abort
All done

This can also be useful to handle unexpected system errors more gracefully:

try:
    for i in [2,1.5,0.0,3]:
        inverse = 1.0/i
except Exception as e: # no matter what exception
    print("Cannot calculate inverse because:", e)
Cannot calculate inverse because: float division by zero