## 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
``````
``````
``````