%matplotlib inline
import matplotlib.pyplot as plt
from math import sin, cos, tan, pi, acos
from graphviz import Digraph

graph_attr = dict(
    rankdir='LR',
#     size='30',
    splines='ortho'
)
start_node = dict(
    shape='box',
    style='rounded, filled',
    fillcolor='#e5f5e0',
    color="#a1d99b"
)
instr_node = dict(
    shape='box',
    style='filled',
    fillcolor='#d9d9d9',
    color="#bdbdbd"
)
branch_node = dict(
    shape="diamond",
    style="filled",
    fillcolor="#cab2d6",
    color="#6a3d9a"
)
dummy_attr = dict(
    shape = "point",
    width = "0",
)

Program Flow and Structure

A program consists of commands, which are executed in a certain order. This order is called the process flow. The following types of structures describe the process flow:

  • Sequence

  • Branching

  • Iteration

With those structures, the process flow can be described by flow charts.

Flowchart en

To illustrate the various structures we will use a package called myturtle.

MyTurtle

MyTurtle is a simple package that is used for educational purposes. It allows to navigate a cursor across a screen, which then draws a line. We need to import the functionality from the package which we want to use. In this case, we need to run

from myturtle import Turtle

We now can create Turtle objects.

t = Turtle()

First the cursor appears at position (0, 0) and points in positive x-direction.

Information about possible commands and their arguments can be accessed with via the documentation of the Turtle class.

Turtle?
Init signature: Turtle(color='k')
Docstring:     
Turtel cursor class

The turtle can turn left or right and move forward. It will draw a line
if drawing is switch on, which it is by default. This version of turtle is
using matplotlib for drawing and may be used in Jupyter notebooks.

Methods:
--------
left(turn=90): turn left by `turn` degrees
right(turn=90): turn right by `turn` degrees
forward(distance=1): move forward by `distance`
set_draw(draw=True): set draw state to either True or False
reset(): reset prosition and angle of the turtle to initial values
File:           ~/anaconda3/envs/pherwiss_programming/lib/python3.8/site-packages/myturtle/turtle.py
Type:           type
Subclasses:     

To get help about a certain method, e.g. forward, use again the ? syntax.

Turtle.forward?
Signature: Turtle.forward(self, distance=1)
Docstring:
Move forward

Parameter:
---------
distance: numeric, default=1. Distance to move forward
File:      ~/anaconda3/envs/pherwiss_programming/lib/python3.8/site-packages/myturtle/turtle.py
Type:      function

Sequence

A Sequence is the simplest process flow. Every command is executed step by step. Every task follows exactly one new task.

Example:

t = Turtle()
t.forward(1)
t.left(120)
t.forward(1)
t.left(120)
t.forward(1)
t.left(120)
../../_images/program_flow_and_structure_11_0.png

The corresponding flow chart looks like this:

Branching

In many cases, one would like the program to execute a task only if a certain condition is met. This is called branching. In Python, as in most other high-level languages, branching is done with an if structure. The syntax is as follows:

if <condition>:
    <conditional code>
<unconditional code>

where <condition> is a statement that can be interpreted as True or False. The part which is only executed conditional must be indented. It does not matter how it is indented, but it must be consistent within the block of conditional code. The convention is to use 4 white spaces for indentation.

Here is an example:

t = Turtle()
t.forward(3.2)
if t.x > 3:
    t.left(180)
    t.forward(t.x - 3)
    t.left(180)
t.left(180)
t.forward(1)    
../../_images/program_flow_and_structure_15_0.png

The corresponding flow chart is

fc = Digraph()
fc.attr(**graph_attr)

for i, (s, attr) in enumerate(zip(
    (
        'start', 'forward(3)', 'x > 3', 'left(180)', 'forward(x - 3)',
        'left(180)', 'left(180)', 'forward(1)', 'end'
    ),
    (start_node, instr_node, branch_node) + 5 * (instr_node,) + (start_node,)
)):
    fc.node(str(i), s, **attr)

fc.edges(['01', '12', '34', '45', '56', '67', '78'])
fc.edge('2', '3', xlabel='yes')
fc.edge('2', '6', xlabel='no', constraint='false')
fc
../../_images/program_flow_and_structure_17_0.svg

The flow chart shows that the process is branched at the purple node. Depending on the result of the condition, only one branch of the program is executed. In this example, there are two possible branches in the process flow. Unlike for sequences, it is now possible that an instruction may follow two preceding ones or two instructions may follow on one preceding one.

The process can also be split into more than two branches using alternative conditions. To do this you use the elif statement together with an condition or the else statement which contains the code if none of the conditions is met. Here is one example and the corresponding flow chart.

t = Turtle()
t.forward(1)
if 1 <= t.x < 2:
    t.left(45)
elif 2 <= t.x < 3:
    t.left(90)
elif 3 <= t.x < 4:
    t.left(135)
else:
    t.left(180)
t.forward(1)
../../_images/program_flow_and_structure_20_0.png

Iteration

In many cases a tasks shall be repeated as long as a specific condition holds or the task shall be executed for each element of a list. For those cases structured programing languages offer loops. In Python, two loop structures are available: the while and the for loop.

While Loop

The while loop executes a code block as long as a specific condition is fulfilled. This code block is called loop body and we say the program iterates the loop body. The syntax is

while <condition>:
    <loop body>

Note that the condition is always checked when entering the loop body. See the example below with the respective flow chart.

t = Turtle()
while t.x <= 5:
    t.forward(1)
../../_images/program_flow_and_structure_24_0.png

break and continue

In all types of loops the iteration can be aborted with a break statement. This terminates the loop and the program jumps to the first instruction after the loop body. A break can be used to define alternative conditions for a while loop or the check the termination condition at a different location in the flow chart.

To only stop the current iteration, the continue statement is used. On encountering a continue, the program jumps to the end of the loop body and starts the next iteration.

See the example below and the corresponding flow chart.

t = Turtle()
while t.x <= 5:
    t.forward(0.1)
    if t.y > 2:
        break
    if t.x > 3:
        continue
    t.left(1)
../../_images/program_flow_and_structure_27_0.png

For Loop

The for loop is a counting loop. The loop body is executed for all elements of a sequence, e.g. a list of integers or any other object. For every iteration the respective object from the sequence is assigned to a variable.

for i in [0, 1, 2, 3]:
    print(i)
0
1
2
3

Of course, loops can also be nested. Here is an example to find all prime numbers between 2 and 99:

for n in range(2, 100):
    for x in range(2, n):
        if n % x == 0:
            break
    else:
        print("{:d} is a prime number".format(n))
2 is a prime number
3 is a prime number
5 is a prime number
7 is a prime number
11 is a prime number
13 is a prime number
17 is a prime number
19 is a prime number
23 is a prime number
29 is a prime number
31 is a prime number
37 is a prime number
41 is a prime number
43 is a prime number
47 is a prime number
53 is a prime number
59 is a prime number
61 is a prime number
67 is a prime number
71 is a prime number
73 is a prime number
79 is a prime number
83 is a prime number
89 is a prime number
97 is a prime number

Useful functions for iterations

Besides range(), python provides further useful functions to iterate over sequences. In particular, the following should be mentioned:

  • enumerate(seq): Returns the elements of a sequence together with a counter.

for i, element in enumerate(['a', 'b', 'c', 'd']):
    print(i, element)
0 a
1 b
2 c
3 d
  • zip(seq1, seq2, …): Takes multiple sequences and returns a tuple of the respective elements for each iteration.

for n, v, a in zip(('ham', 'spam', 'eggs'),
                   ('is', 'was', 'has been'),
                   ('good', 'mouldy', 'sticky')):
    print(n, v, a)
ham is good
spam was mouldy
eggs has been sticky