NB: Control Structures

Programming for Data Science

Introducing Control Structures

Python includes structures to control the flow of data in a program.

These structures are made of code blocks that provide looping and branching capabilities to your code, based on boolean conditions.

Control structures are fundamental to creating algorithms that can process and respond to data as it flows through and is transformed by a program.

Conditions

Conditions are boolean checkpoints in a program, switching a process based on wheter some condition is true or not.

The if and else keywords can be used to create branches in your code based on conditions.

This is called conditional processing.

Here is a very simple example.

val = -2

if val >= 0:
    print(val)
else:
    print(-val)
2

A Note about Indentation

Note the indenation pattern in the code:

if val >= 0:
    print(val)
else:
    print(-val)

This is where Python differs from most languages.

To define control structures, and functional blocks of code in general, most languages use either characters like braces { and } or key words like IF ... END IF.

For example, here is how this control structure might look in other languages:


if (val <= 0) {
    print(val);
} 
else {
    print(-val);
}

Or:

IF val <= 0
    PRINT val
ELSE
    PRINT -val
END IF

Python uses tabs — spaces, actually — to signify logical blocks off code.

It is therefore imperative to understand and get a feel for indentation.

elif

elif is reached when the previous statements are not.

Note that if one succeeds, those that follow are not processed.

This is unlike a series of if statements.

val = -2

if -10 < val < -5:
    print('bucket 1')
elif -5 <= val < -2:
    print('bucket 2')
elif val == -2:
    print('bucket 3')
bucket 3

else

else can be used as a catch-all for situation when no condition is met.

val = 5

if -10 < val < -5:
    print('bucket 1')
elif -5 <= val < -2:
    print('bucket 2')
elif val == -2:
    print('bucket 3')
else:
    print('bucket 4')
bucket 4

It’s a good practice to include an else statement.

if and else as one-liners

Python provides a short-hand way of defining if statements.

x = 3

print('odd') if x % 2 == 1 else print('even')
odd

The general form:

ACTION1 if CONDITION else ACTION2

Both if and else are required. This breaks:

print('odd') if x % 2 == 1
SyntaxError: expected 'else' after 'if' expression (471325368.py, line 1)

Essentially, then, this is an either/or construct.

Using multiple conditions

If statements can be complex combinations of expressions. Use parentheses to keep order of operations correct.

Correct:

print(1) if (-2 < val < 2) or (val > 10) else print(2)
2

Incorrect:

print(1) if (-2 < val) < 2 or val > 10 else print(2)
1

The problem is that the condition line is interpreted as True < 2, where True is cast to integer value \(1\).

Loops

Loops are fundamental constructs in programming.

They allow for the repeated application of a set of operations on a series of values to compute a result.

The repetition of a process as the data changes is called iteration.

A loop is an algorithmic pattern designed to process data stored in a seqeuence of some kind, such as provided by a list or range.

Loops exemplify a premise of this course that data structures imply algorithms. Using the term ‘list’ broadly, we may say that Lists imply loops.

There are two main kinds of loops in Python: while and for.

while loops

While loops iterate while some condition is true. It stops when the condition is false.

Here is a simple example:

ix = 1
ix_list = []
while ix < 10:
    ix *= 2
    ix_list.append(ix)
print(ix)
print(ix_list)
print(ix_list[-1])
16
[2, 4, 8, 16]
16

Note that it is possible for while loops to be unending.

For example:

while 1:
    print("This is so annoying")

This is why it is important to make sure that your looping condition can be met.

You may also break out of a loop by other means.

break

Sometimes you want to quit the loop early, if some condition is met.

To do this, put break in an if statement.

ix = 1
while ix < 10:
    ix = ix * 2
    if ix == 4:
        break
print(ix)
4

The break causes the loop to end early

continue

Sometimes you want to introduce skipping behavior in the loop.

To do this, put continue in an if statement.

ix = 1
while ix < 10:
    ix = ix * 2
    if ix == 4:
        print('skipping 4...')
        continue
    print(ix)
2
skipping 4...
8
16

See how continue causes the loop to skip printing \(4\).

for

In contrast to while loops, for loops iterate over an iterable data structure, such as a list.

They stop when the list is finished.

cities = ['Charlottesville','New York','SF','BOS','LA']

for city in cities:
    print(f'"{city.lower()}"', end=' ')
"charlottesville" "new york" "sf" "bos" "la" 

Conditions can be used inside of if statements to skip within or stop the loop.

Quit early if SF reached, using break:

cities = ['Charlottesville','New York','SF','BOS','LA']

for city in cities:  
    if city == 'SF':
        break
    print(f'"{city.lower()}"', end=' ')
"charlottesville" "new york" 

Skip over SF if reached, using continue:

cities = ['Charlottesville','New York','SF','BOS','LA']

for city in cities:
    if city == 'SF':
        continue
    print(f'"{city.lower()}"', end=' ')        
"charlottesville" "new york" "bos" "la" 

while vs for

When choosing between for and while loops, consider this:

  • for loops are used to loop through a list of values or an operation in which the number of iterations is known in advance.

  • while loops are when you don’t know how many interations it will take — you are depending on some condition to be met.

The former is often used when processing data, the latter when performing algorithmic modeling tasks, such as optimization and convergence.