Course Module • Jillur Quddus

3. Control and Evaluations Part 2

Introduction to Python

Control and Evaluations Part 2

Introduction to Python

Jillur Quddus • Founder & Chief Data Scientist • 1st September 2020

  Back to Course Overview

Introduction

In this module we will continue to cover the fundamental building blocks of the Python programming language, namely:

  • Functions and Methods - the difference between methods and functions
  • Input and Output - input, print, int, float and str functions
  • Formatting - formatting the output of the print function, and formatted string literals
  • Conditional Statements - if, if-else, if-elif, if-elif-else statements and the pass instruction
  • Basic Lists - constructing, accessing and manipulating list data collection structures
  • Basic Strings - constructing, accessing and operating on string literals
  • Loops - while loops, for loops, and controlling loops using break and continue statements

The source code for this module may be found in the public GitHub repository for this course. Where code snippets are provided in this module, you are strongly encouraged to type and execute these Python statements in your own Jupyter notebook instance.

1. Functions and Methods

Throughout this course we will explore common functions and methods available in Python. But what exactly are functions and methods, and what is the distinction between the two?

We will explore functions in further detail in the Functions and Modules Part 1 module of this course. However at a high-level, functions are blocks of code designed to undertake a specific task. A function may expect zero or more parameters or arguments to be passed to it by the code calling the function. And a function may return zero or more values. Provided below is an example function called product() that expects to be given two numbers number_1 and number_2. The product() function will then return the product of these two numbers.

# A simple function to return the product of two given numbers
def product(number_1, number_2):
    return number_1 * number_2

print(product(12, 20))

Another example of a function is the common len() function that is provided by the Python standard library and which will return the number of elements in a given object. When given a string, it will return the number of characters in that string.

# The common len() function given a string
my_string = 'Hello World!'
print(len(my_string))

Methods are a subclass of functions, and are operations associated with specific object types or classes. We will explore classes in further detail in the Classes and Objects Part 1 module of this course. However at a high-level, methods apply their operations on the object on which it is invoked. Provided below is an example string method called str.upper() that will transform all the characters in the given string object into uppercase.

# A common string method that will return the string all in uppercase
my_string = 'Hello World!'
print(my_string.upper())

2. Input and Output

At the most basic level, most computer programs are a collection of instructions that, given one or more inputs, will execute those instructions and generate one or more outputs. Sometimes inputs and outputs may be hidden from the user of the program - for example an input may be an update to a database that triggers a computer program to run. There are times however that a computer program requires input from the user - for example the input of their name, address or date of birth, and the output to be printed in a human-readable form. In Python, this is enabled by the input() and print() functions respectively.

2.1. Input Function

In Python the input() function allows user input, with an optional string parameter that represents a prompt message that will be displayed before the input, as follows:

# Input function without a prompt message argument
full_name = input()
print(f'Your Full Name is: {full_name}')

# Input function with a prompt message argument
fname = input('Please enter your first name: ')
lname = input('Please enter your last name: ')
print(f'Hello {fname} {lname}!')

By default, the variables above are assigned the string literal value of the user input. In order to restrict user input to other types of literals, such as integer and floating point literals, Python provides the int() and float() functions as described in the following sub-sections.

Note that the int(), float() and str() functions may be used independent of the input() function.

2.2. Int Function

The int() function will covert a given number or string into an integer number. We may also provide an optional base parameter that represents the numeral base system - by default this is base 10. To use the Hexadecimal numeral base system for example, we would provide 16 as the optional base parameter.

To learn more about number base systems, please refer to Number Bases.

# Integer input using the int function (default base 10)
age = int(input('Please enter your age: '))
print(f'You are {age} years old')

# Integer input using the int function and base 16
# For example 28 (base 10) would be 1c in base 16
age = int(input('Please enter your age: '), 16)
print(f'You are {age} years old')

Note that if we passed a floating point number to the int() function, it would return the integer part of that number. It would NOT perform any rounding.

2.3. Float Function

The float() function will convert a given number or string into a floating point number.

# Floating point input using the float function
height = float(input('Please enter your height in metres: '))
print(f'You are {height}m tall')

2.4. Str Function

The str() function will try to convert any given object into a string, and if no object is provided then an empty string is returned. The primary purpose of the str() function is to return a human-readable form of a given object. In the following example, we need to use the str() function when concatenating a numeric value to a string.

# Without the str function we cannot concatenate a number to a string
pi = 3.141592653589793238462643
print('The value of π is: ' + pi)

# The str function will convert pi into a string
print('The value of π is: ' + str(pi))

2.5. Print Function

In the examples above you will have noticed the use of the print() function. In Python, the print() function will convert any given object into a string before printing that string to the standard output device, normally the Python console but which may also be a log file or similar. If more than one object is provided to the print() function, then we may also define a separator character or sequence to act as a delimiter (the default of which is the space character). Finally we may optionally define an end sequence that specifies what to print at the end of the output (by default this is a new line feed \n).

# Print a given string
print("My name is Jillur Quddus")

# Print a given collection of strings
print("Software Engineer", "Data Scientist", "Technical Architect")

# Print a given collection of strings with a separator
print("Software Engineer", "Data Scientist", "Technical Architect", sep=', ')

# Print a list of occupations on the same line
print("My Roles", end=": ")
print("Software Engineer", "Data Scientist", "Technical Architect", sep=', ')

3. Formatting

3.1. Formatted String Literals

In addition to the end and sep arguments introduced above, you may also have noticed the use of the f character in the print() function before the opening quotation mark. This enables us to use formatted string literals (f-strings for short) in Python, that is resolving and using the value of Python expressions inside a string itself. To resolve and use the value of a Python expression in an f-string, we write the Python expression between { and } characters. In the examples above, we simply refer to Python variables with any literal value. But we may also use more complicated Python expressions as well, as follows:

# Print the value of e (Eulers number) using formatted string literals
e = 2.718281828459045235360287
print(f'The value of e is {e}')

# Print the value of e but to 3 decimal points
print(f'The value of e to 3 decimal points is {e:.3f}')

# Print age as a number of days
age = int(input('Please enter your age: '))
print(f'You are at least {age * 365} days old')

Note that an easier (and recommended) way to access common mathematical constants is to use the math module found in the Python standard library, as described in the following code snippet.

# Access common mathematical constants using the Pythom math module
import math
print(f'The value of π to 3 decimal points is {math.pi:.3f}')
print(f'The value of e to 3 decimal points is {math.e:.3f}')

4. Conditional Statements

Conditional statements are a feature of all programming languages - they allow the developer, and hence the computer program, to perform different computations and actions dependent on whether a boolean condition evaluates to true or false. Dependent on which condition is met, a different control flow branch is selected and executed. Python differs from many programming language in that the subsequent code following a conditional statement must be indented in order for the Python interpreter to correctly identify which code block forms the required control flow to execute.

4.1. If Statement

The most commonly used conditional statement is the if statement. The if statement supports, amongst others, the comparison, logical, identity and membership operators covered in Control and Evaluations Part 1. It allows the developer to define a condition known as a conditional expression - if the expression evaluates to the boolean value of True then the subsequent and indented code block is executed. A series of conditions may be defined using logical operators - if the entire series of conditions evaluate to True then the subsequent and indented code block is executed. The if statement and conditional expression is separated from the subsequent and indented conditional code block by the colon : character.

# If statement using a comparison operator
age = int(input('Please enter your age: '))
if age >= 18:
    print("You are allowed to vote in UK elections")

# If statement using comparison and logical operators
if age >= 16 and age < 21:
    print("You are allowed to work full-time, join the armed forces, drive and vote but you cannot yet adopt a child in the UK")

# If statement using identity and logical operators
a = 10
b = 20
c = a

if a is b:
    print("a and b are the same object at object memory level")
if a is c:
    print("a and c are the same object at object memory level")
if b is c:
    print("b and c are the same object at object memory level")

# If statement using a membership operator
first_ten_prime_numbers = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
if 13 in first_ten_prime_numbers:
    print("13 is in the first ten prime numbers")

4.2. If-else Statement

The if-else conditional statement extends the if statement by providing a means to define another indented code block that is executed if the given conditional expression evaluates to the boolean value of False. Note that the else keyword is optional when writing if statements.

# If-else statement using a comparison operator
age = int(input('Please enter your age: '))
if age >= 18:
    print("You ARE allowed to vote in UK elections")
else:
    print("You are NOT yet allowed to vote in UK elections")

4.3. If-elif Statement

The if-elif conditional statement extends the if statement by providing the means to define an indefinite number of else-if conditions, and subsequent indented code blocks to be executed, if the first conditional expression is not met. Note that the elif keyword is optional when writing if statements. If-elif may be optionally combined with the else keyword to define a comprehensive control flow block, where the else condition is evaluated if neither the first conditional expression nor any of the subsequent elif conditional expressions evaluate to True.

# If-elif statements using comparison and logical operators
age = int(input('Please enter your age: '))
if age >= 21:
    print("You are entitled to undertake all legally permissible activities in the UK")
elif age >= 14 and age < 16:
    print("You can get a part-time job in the UK")
    print("But you cannot work full-time nor get married in the UK")
elif age >=16 and age < 18:
    print("You can get a full-time job and get married in the UK")
    print("But you cannot yet vote in the UK")
elif age >=18 and age < 21:
    print("You can get a full-time job, get married and vote in the UK")
    print("But you cannot adopt a child in the UK")
else:
    print("You can't do by yourself much unfortunately")
    print("Stay in school and listen to your parents!")
    if age >= 10:
        print("But since you greater than 10 years old, you have full criminal responsibility for your actions and can be convicted of a criminal offence in the UK")
        print("So think before you act!")

Note that a code block that is conditionally executed may contain one or more statements. Python determines the start and end of a conditional code block by analysing its indentation levels, where all statements in a conditional block must be no less indented than the first statement in the conditional block. Refer to the conditional code block above and after the else keyword as an example of this.

4.4. Pass Statement

The pass statement in Python is a null statement where nothing is executed. It is used when a statement is required syntactically, but the developer has not yet defined the code to be executed and instead wishes to put in a placeholder for future code. The Python interpreter does not allow empty code blocks in if statements, loops, function definitions nor class definitions - if an empty statement is found, then an indentation error is raised. The pass statement is commonly used with if statements within loops as we shall cover later in this module.

# Use the pass statement to only print if x is even
x = int(input('Please enter an integer number: '))
if x % 2 != 0:
    pass
else:
    print(f"{x} is an even number")

5. Basic Lists

In Python there are four built-in data structures that are designed to hold collections of data in such a way that enables quick and efficient operations on that data, such as insertion, deletion and retrieval operations. These are lists, tuples, sets and dictionaries. In this subsection we will focus on lists. A list in Python is an ordered and mutable (changeable) collection where duplicate elements (members/items) are allowed. Each element in a list is an object in its own right, whether a basic literal or more complicated object.

5.1. Defining a List

A list in Python is created by using square brackets []. Lists may be instantiated with its initial contents or as an empty list as follows.

# Create an empty list
empty_list = []

# Create a list containing the first five square numbers
squares = [1, 4, 9, 16, 25]
print(squares)

5.2. Index and Negative Indexing

Each individual element in a list can be accessed by referencing its index number. The first element in a list has index number 0, the second element has index number 1 and so on. We may also access an element by its negative index number. The last element in a list has a negative indexing of -1, the penultimate element has a negative indexing of -2 and so on.

# Access elements in a list by their index numbers
print(squares[0])
print(squares[3])
print(squares[-1])
print(squares[-4])

5.3. List Slicing

Slicing notation enables us to access and manipulate a specific subset of elements from a list in an efficient manner (it also works with string literals). It works by referencing a range of index numbers inside square brackets [:], from a start index number (to the left of the colon) to an end index number (to the right of the colon). If a start index number is NOT provided, then Python will start from index number 0. If an end index number is NOT provided, then Python will return elements including the last element in the list. If an end index number IS provided, then Python will return elements up until, but NOT including, the element at that index number. Slicing also supports negative indexing as follows.

# Slicing a list
print(squares[0:2])
print(squares[2:])
print(squares[:3])
print(squares[:])
print(squares[-3:-1])
print(squares[-1:])
print(squares[:-2])

Note that if we specify an end index that is beyond the range of the number of elements in question, Python will handle this situation gracefully. In this case, it will default to the length of the object rather then raising an exception, as follows:

# Define an end index that is purposefully too large
print(squares[0:100])

5.4. List Length

The Python len() function allows us to calculate the number of elements in a list (or another type of collection).

# Length of a list
print(f'The length of the squares list is: {len(squares)} elements')

5.5. List Membership

The membership in operator, as discussed in Control and Evaluations Part 1, allows us to test whether a given element can be found within a given list (or another type of collection).

# Test whether an element exists in a list
x = 169
if x in squares:
    print(f"{x} exists in our list of square numbers")
else:
    print(f"{x} does not exist in our list of square numbers")

5.6. Modifying Elements in a List

We can change the value of a specific element by referencing its index number and assigning a new value. This modifies the list 'in place' - that is the operation does not return a new list object but instead modifies the original list.

# Modify a specific element in a list
squares[0] = 0
print(squares)

# Revert to the original value
squares[0] = 1
print(squares)

5.7. Deleting Elements and Lists

One way to remove specific elements from a list in place is to use the del keyword followed by the list and the relevant index number. If we apply the del keyword to the list without an index, it will delete the list collection object completely.

# Remove a specific element from a list
del squares[-1]
print(squares)

# Delete a list collection entirely
del empty_list
print(empty_list)

5.8. Joining Lists

One way to join one list to another list (NOT in place) is to use the + operator. This will append all the elements from one list to the other list.

# Append all elements from more_squares to squares
more_squares = [25, 36, 49, 64, 81, 100]
updated_squares = squares + more_squares
print(updated_squares)

5.9. List Methods

The list collection in Python provides the following common methods on the list object which can be used to access, insert, modify, copy and delete list elements.

  • list.append(element) - adds an element to the end of the list and in place
  • list.extend(newlist) - appends all the elements in the given new list to the original list and in place
  • list.insert(index, element) - inserts a given element at the given index number position and in place, shifting the latter elements to the right
  • list.remove(element) - removes the first element instance in the list whose value is equal to the given element, and in place. If no matching instance is found, then Python will raise a ValueError exception. This can be avoided by first using the membership operator in an if statement to test for existence before removal, or handling the exception.
  • list.pop([index]) - removes the element at the given index and returns it. The index number is optional, and if no index is given then the list.pop() method will simply remove the last element in the list and return it
  • list.clear() - removes all the elements from the list. This is equivalent to del list[:]
  • list.index(element[, start[, end]]) - searches for the first element instance in the list whose value is equal to the given element and returns its index number. f no matching instance is found, then Python will raise a ValueError exception. This can be avoided by first using the membership operator in an if statement to test for existence before removal, or handling the exception. Optionally we may provide slice index numbers to limit the search to a subset of elements.
  • list.count(element) - returns the number of element instances whose values are equal to the given element
  • list.sort() - sorts the elements in the list and in place
  • list.reverse() - reverses the elements in the list and in place
  • list.copy() - returns a copy of a list, the equivalent of list[:]. Note that by simply assigning a variable to the list object will NOT make a copy but will instead only make a reference to the original list object. This means that any changes made to the original list will be reflected in the new variable automatically.
# list.append(element)
squares.append(25)
print(squares)

# list.extend(newlist)
del more_squares[0]
squares.extend(more_squares)
print(squares)

# list.insert(index, element)
squares.insert(0, 0)
print(squares)

# list.remove(element)
squares.remove(0)
print(squares)

# list.pop([index])
squares.pop()
print(squares)

# list.clear()
squares.clear()
print(squares)

# Populate the list of square numbers again
squares.extend([1, 4, 9, 16, 25, 36, 49, 64, 81, 100])

# list.index(element[, start[, end]])
print(squares.index(64))

# list.count(element)
print(squares.count(169))

# list.sort()
squares.sort()
print(squares)

# list.reverse()
squares.reverse()
print(squares)

# list.copy()
squares_copy = squares.copy()
print(squares_copy)

6. Basic Strings

As introduced in Control and Evaluations Part 1, string literals are sequences of characters enclosed within either single or double quotes. Represented as a data structure, strings are in actual fact sequences of bytes representing unicode characters. Since they are sequences, this means that they can be accessed and operated upon similar to lists. However, unlike lists, strings in Python are immutable, meaning that once created they cannot be changed. Any operations on strings will result in the creation of a new string object.

6.1. Creating Strings

Strings can be created by simply enclosing values with either single ' or double quotes ". Multiline strings can be instantiated using three double quotes """ as follows.

# Create a simple string
first_name = 'Jillur'
print(first_name)

# Create a multiline string
envelope_label = """Jillur Quddus
1600 Pennsylvania Ave NW
Washington
DC 20500
United States"""
print(envelope_label)

6.2. Index and Slicing

Since strings are in actual fact sequences of bytes, we can access individual characters within a string by referencing their index number. Note that like lists, strings are also zero-indexed. Furthermore, we can access and extract subsequences of characters using slicing notation, again similar to lists. Note that Python does not have a character literal type like some other programming languages. Instead a character is simply a string of length 1.

# Create a simple string
lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."

# Print the 13th character
print(lorem_ipsum[12])

# Print the substring between the 29th and 56th characters
print(lorem_ipsum[28:55])

# Print the last word
print(lorem_ipsum[-7:-1])

6.3. String Length

The Python len() function allows us to calculate the number of characters in a string.

# Calculate the length of a string
print(len(lorem_ipsum))

6.4. String Membership

The membership in operator, as discussed in Control and Evaluations Part 1, allows us to test whether a given sequence of characters can be found within a given string.

# Test whether a given sequence of characters can be found in a string
if "tempor" in lorem_ipsum:
    print("The latin word for time has been found!")

6.5. Concatenating Strings

One way to concatenate one string to another string (generating a new string since strings are immutable) is to use the + operator.

# Concatenate one string to another string
lorem_ipsum_continued = "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
lorem_ipsum_updated = lorem_ipsum + " " + lorem_ipsum_continued
print(lorem_ipsum_updated)

6.6. Escape Character

In some cases, the inclusion of specific characters in a string literal will cause Python to raise a SyntaxError exception - for example the existence of a double quote character in a string that itself is defined and enclosed by double quote characters. To overcome this, we may 'escape' those illegal characters by prefixing them with the \ backslash character as follows.

# Try to create a string containing illegal characters
illegal_string = "My name is "Jillur""

# Escape the illegal characters using the backslash character
legal_string = "My name is \"Jillur\""
print(legal_string)

Other escape characters in Python include:

  • \' - single quote
  • \" - double quote
  • \\ - backslash
  • \b - backspace
  • \n - new line
  • \r - carriage return
  • \t - tab

6.7. Raw and Unicode String Literals

As discussed in Control and Evaluations Part 1, to create a raw string literal, that is to ignore backslashes and treat them as literal characters, we can prefix string literals with r. To create unicode string literals, that is to support unicode characters, we can prefix the string literal with u.

# Create and print a raw string literal
raw_string_literal = r"My name is Jillur Quddus\nI am a Chief Data Scientist and Principal Polyglot Software Engineer. Please find attached my résumé"
print(raw_string_literal)

# Create and print a unicode string literal
unicode_string_literal = u"My name is Jillur Quddus\nI am a Chief Data Scientist and Principal Polyglot Software Engineer. Please find attached my résumé"
print(unicode_string_literal)

Note that a unicode string in Python is actually a different type of object than the regular string type. However since they both inherit from the same superclass, the difference is not normally noted by beginner Python developers.

6.8. Comparing Strings

In Python, unlike some other programming languages such as Java, the == equality comparison operator is designed to compare string values. Note that == peforms an exact match comparison on values, so if the strings have a case mismatch then the result of the comparison will be False.

# Compare two strings
individual1_first_name = "Jillur"
individual2_first_name = "jillur"
if individual1_first_name == individual2_first_name:
    print("Both individuals share the same first name")
elif individual1_first_name.upper() == individual2_first_name.upper():
    print("Both individuals share the same first name when uppercased")
else:
    print("No name match found")

6.9. String Methods

Python provides the following common but non-exhaustive string methods.

  • str.lower() - returns the string all in lowercase
  • str.upper() - returns the string all in uppercase
  • str.strip() - returns the string with leading and trailing whitespace characters removed
  • str.replace('find', 'replacewith') - returns the string with all instances of the first substring replaced with the second substring
  • str.find('substring') - returns the starting index of the first instance of the given substring, else returns -1 if no match is found
  • str.startswith('substring') - tests whether the string starts with the given substring
  • str.endswith('substring') - tests whether the string ends with the given substring
  • str.split('delimiter') - returns a list collection of substrings by splitting the original string on a given delimiter. If no delimiter is provided, then the string is split on all whitespace characters
  • delimiter.join([list]) - returns a string that joins all of the elements in a given list collection together using the given string delimiter
# Create a new string literal
my_string = "    Hello! My name is Jillur Quddus and I am a Chief Data Scientist and Principal Polyglot Software Engineer.    "
print(my_string)

# str.lower()
print(my_string.lower())

# str.upper()
print(my_string.upper())

# str.strip()
stripped_string = my_string.strip()
print(stripped_string)

# str.replace('find', 'replacewith')
initialized_string = stripped_string.replace('Jillur', 'J').replace('Quddus', 'Q')
print(initialized_string)

# str.find('substring')
print(initialized_string.find('Data Scientist'))

# str.startswith('substring')
print(initialized_string.startswith('Hello!'))

# str.endswith('substring')
print(initialized_string.endswith("Good Bye!"))

# str.split('delimiter')
print(initialized_string.split('!'))

# delimiter.join([list])
print('|'.join(['Chief Data Scientist', 'Principal Polyglot Software Engineer', 'Technical Architect']))

7. Loops

All programming languages provide special control flow statements called loops that allow for iteration, either over a data structure or whilst a boolean condition is met. Python provides two primitive loops - the while loop and the for loop.

7.1. While Loop

The while loop is a control flow statement where an indented code block of one or more statements is repeatedly executed whilst a boolean condition continues to be true. When that boolean condition is no longer true, the while loop is exited. The example below calculates the factorial of a given positive integer number. First it prompts the user for a positive integer value, which it assigns to the variable n. It then creates two integer literals, namely factorial and counter, which are both set to the value of 1. The while loop is then defined with a conditional expression so that the subsequent indented code block is repeatedly executed whilst the value of counter is less than or equal to the value of n. Whilst this condition is true, the value of factorial is multiplied by the current value of counter, and the value of counter incremented by 1 at the end of each iteration. When the value of counter is greater than n, the while loop is exited and the factorial value is displayed.

# Calculate the factorial of a given positive integer using a while loop
n = int(input('Please enter a positive integer value: '))
if n < 1:
    print('Please enter a positive integer value.')
else:
    factorial = 1
    counter = 1
    while counter <= n:
        factorial *= counter
        counter += 1
    print(f'The factorial of {n} is {factorial}')

7.2. While-else Loop

The while loop can be extended by using the else statement to run another indented code block when the condition of the while loop is no longer true. The example below calculates the sum of the first 10 positive integer values.

# Calculate the sum of the first 10 positive integer values using a while loop with else
counter = 1
sum = 0
while (counter <= 10):
     sum += counter
     counter += 1
else :
     print(f'The sum of first 10 positive integer values is {sum}')

7.3. For Loop

The for loop is a control flow statement when an indented code block of one or more statements is repeatedly executed. The use case of a for loop in Python differs slightly from other programming languages in that it is used to iterate through data structures and sequences (in other programming languages such as Java, the for loop can also be used to iterate over a range with no further functions required). In the example below, we use the for loop in Python to iterate over a list collection of string literals and print both the current element in the list and its string length. Note that the for loop can also be used to iterate over tuples, dictionaries, sets and strings, since strings are arrays of bytes as we discovered earlier. The example below iterates through a shopping list of string literals. For each iteration of the for loop, the value of the current element is assigned to the variable shopping_item using the in keyword. The indented code block then prints both the current element and its string length using the len() function.

# Iterate over a list of strings and print each element and its string length
shopping_list = ['Apples', 'Bananas', 'Potatoes', 'Tomatoes', 'Milk', 'Cheese', 'Bread', 'Eggs', 'Butter']
for shopping_item in shopping_list:
    print(f'{shopping_item}: {len(shopping_item)}')

7.4. Range Function

In Python, the range() function in conjunction with a for loop and in keyword allows us to execute an indented code block a specified, explicit and deterministic number of times. The range(x) function with a single argument x returns a sequence of numbers starting from 0 up until but NOT including x, incrementing by 1. The range(x, y) function with two arguments returns a sequence of numbers starting from x up until but NOT including y, incrementing by 1. The range(x, y, i) function with three arguments returns a sequence of numbers starting from x up until but NOT including y, incrementing by i.

# Range function with a single argument
for n in range(10):
    print(n)

# Range function with two arguments
for n in range(10, 20):
    print(n)

# Range function with three arguments
for n in range(10, 20, 2):
    print(n)

7.5. For-else Loop

The for loop can be extended by using the else statement to run another indented code block when the loop has finished.

# Attempt to enter a password three times using a for loop with the range function and else statement
for n in range(3):
    password_attempt = input('Please enter your password: ')
    if password_attempt == 'Passw0rd123!':
        print('Successful authentication')
        break
else:
    print('Your account has been locked after 3 failed attempts to login.')
    print('Please contact your system administrator to unlock your account.')

7.6. Break Statement

In the example above, we use the break statement to terminate and exit the for loop if a conditional expression defined within the for loop is evaluated as true. In the example, we terminate and exit the for loop if the user enters the correct password. The break statement can be used in both while and for loops respectively. In the guessing game example below, we terminate and exit the while loop using the break statement if the user guesses the correct number, or if the user exceeds the defined number of guesses allowed.

# Guess the number game demonstrating the break statement in a while loop
import random
random_number = random.randint(1, 30)
guess_counter = 0
guess_limit = 5
print('******** Guess the Number! ********')
print(f'I am thinking of a number between 1 and 30. Can you guess it in less than {guess_limit} attempts?')
while guess_counter < guess_limit:
    guess = int(input(f'Attempt #{guess_counter + 1} Enter your guess: '))
    guess_counter += 1
    if guess < random_number:
        print('Too low!')
    elif guess > random_number:
        print('Too high!')
    else:
        break

if guess == random_number:
    print(f'Congratulations! You guessed correctly in {guess_counter} attempts!')
else:
    print(f'Sorry! Game Over! The number I was thinking of was {random_number}.')

7.7. Continue Statement

The continue statement is used for when we wish to stop the current iteration of the loop but we do NOT want to terminate the loop entirely. The continue statement can be used in both while and for loops respectively. In the examples below, we use the continue statement in a for loop to print all non-dairy items from a given shopping list. We then use the continue statement in a while loop to print only the odd numbers in a given range.

# Print only non-dairy products from a shopping list using a for loop and continue statement
shopping_list = ['Apples', 'Bananas', 'Potatoes', 'Tomatoes', 'Milk', 'Cheese', 'Bread', 'Eggs', 'Butter']
dairy_products = ['Milk', 'Cheese', 'Eggs', 'Butter']
for shopping_item in shopping_list:
    if shopping_item in dairy_products:
        continue
    print(shopping_item)

# Print only the odd numbers in a given range using a while loop and continue statement
n = 0
while n < 10:
    n += 1
    if n % 2 == 0:
        continue
    print(n)

7.8. Nested Loops

A nested loop is a loop inside another loop. The first loop that is defined is called the outer loop, and the subsequent loops are called inner loops. For each single iteration of the outer loop, the inner loop is fully executed through to completion or until it is terminated by a break statement. Theoretically we could define an indefinite number of nested loops, but it quickly becomes difficult to decipher our Python code beyond two or three nested loops so it is not recommended unless it is genuinely required - such as iterating over multi-dimensional data structures employed in linear algebra for example. In the example below, we define a for loop within a for loop in order to render a rectangle of given dimensions using a given fill character.

# Render a rectangle of a given dimension using nested for loops
number_columns = 5
number_rows = 5
fill_character = '*'
for row in range(number_rows):
    print(fill_character, end=' ')
    for column in range(number_columns - 1):
        row *= column
        print(fill_character, end=' ')
    print('')

Summary

In this module we have continued to cover the fundamental building blocks of the Python programming language. We have gained the ability to prompt the user for input, and to display formatted output. We also have an understanding of primitive control flow statements including conditional statements and loops, and have gained the ability to create, operate on and modify list data structures and string literals.

Homework

Please write Python programs for the following exercises. There may be many ways to solve the challenges below - first focus on writing a working Python program, and thereafter look for ways to make it more efficient using the techniques discussed over the last two modules.

  1. Fibonacci Sequence
    Write a Python program that prompts the user for a positive integer value, and then returns the Fibonacci sequence from 0 up until (and including if appropriate) the integer value provided by the user. For example, if the user entered the number 1000, then your Python program would print "0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987".

  2. Prime Numbers
    Write a Python program that, for any two positive integer values x and y, returns ALL the prime numbers between x and y. For example if x = 20 and y = 100, then your Python program would print "23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97".

  3. First Prime Number
    Write a Python program that, for any two positive integer values x and y, returns only the FIRST prime number between x and y. For example if x = 8750 and y = 9999, then your Python program would print "8753".

What's Next?

In the next module, we will cover strings and lists in more detail including advanced slicing techniques, character encodings, common methods and functions that can be applied to strings and lists, and how to create multi-dimensional arrays and matrices.