This lesson is in the early stages of development (Alpha version)

Python for Absolute Beginners

Help and Documentation

Overview

Teaching: 5 min
Exercises: 0 min
Questions
  • Where can you find more help and documentation?

Objectives
  • Know where to get further help.

Help and documentation

Official Python Documentation

W3Schools

GeeksforGeeks


Key Points


Data Types

Overview

Teaching: 20 min
Exercises: 0 min
Questions
  • What kind of data types exist in Python?

  • What are the key differences between the data types?

Objectives
  • Understand the essential data types in Python

  • Explain what a string is, and what you can do with it

  • Explain the differences between integers and floats

  • Explain what a boolean is, and how to use comparisons

Data Types

There are four essential kinds of Python data with different powers and capabilities:

Take a look at the two examples below.
What differences do you notice?

'Here is a some text'
42

You might be wondering…

Why is ‘Here is some text’ surrounded by quotation marks while 42 is not?
Because these are two different “types” of Python data. We will look closer at the different types below.
Note, that many Python editors and environments (such as Juptyter Lab etc.) will colour the output based on data type. E.g. in Jupyter Lab strings will be in red and integers in green.

Data Type

Explanation

Example

String

Text

'Anything goes 4 strings!'

Integer

Whole Numbers

42

Float

Decimal Numbers

3.1415926

Boolean

True/False

False

Check Data Types

You can check the data type of any value by using the function type().

type('Here is some text')
str

The output str is short for string.

type(42)
int

The output int is short for integer.

Strings

A string is a Python data type that is treated like text, even if it contains a number. Strings are always enclosed by either single quotation marks 'this is a string' or double quotation marks "this is a string".

'this is a string'
"this is also a string, even though it contains a number like 42"
this is not a string

It doesn’t matter whether you use single or double quotation marks with strings, as long as you use the same kind on either side of the string.

Bonus

How can you have quotation marks inside a string?

Escape characters

Escape characters and how to tell Python to igonre special meanings. This can be handy if you need to make quotation marks inside a string. This can be done in two ways.

Use the opposite kind of quotation mark inside the string:

"She exclaimed, 'This is a quotation inside a string!'"

Or “escape” the quotation mark by using a backslash \ before it:

"She exclaimed, \"This is also a quotation inside a string!\""

String Methods

Each data type has different properties and capabilities. So there are special things that only strings can do, and there are special ways of interacting with strings.

For example, you can index and slice strings, you can add strings together.
Here are a few examples:

Index

Often in programming languages, individual items in an ordered set of data, can be accessed directly using a numeric index or key value. This process is referred to as indexing.

In Python, strings are ordered sequences of character data, and thus can be indexed in this way. Individual characters in a string can be accessed by specifying the string name followed by a number in square brackets [].

String indexing in Python is zero-based: the first character in the string has index 0, the next has index 1, and so on. The index of the last character will be the length of the string minus one. It can be illustrated like this:

index

The individual characters can be accessed by index:

'I am a string'[0]
'I'
'I am a string'[7]
's'

Slice

Python allows a form of indexing syntax that extracts substrings from a string, known as string slicing.
If s is a string, an expression of the form s[start:stop] returns the portion of s starting with position start, and up to but not including position stop:

'I am a string'[0:8]
'I am a s'

Concatenation

The + operator concatenates strings. It returns a string consisting of the operands joined together, as shown here:

'I am a string' + ' and so am I'
'I am a string and so am I'

Notice that we have added a space in the beginning of the second string, otherwise there would be no space between ‘string’ and ‘and’. You can also add a space between two strings like this:

'I am a string' + ' ' + 'and so am I' 
'I am a string and so am I'

Integers & Floats

An integer and a float are two Python data types for representing numbers.

Integers and floats do not need to be placed in quotation marks.

type(42)
int
type(3.1415926)
float

Mathematical operations

You can do a large range of mathematical calculations and operations with integers and floats. Here are a few examples, for an extended overview you can fold out a table at the end of this section.

Multiplication

You can multiply in Python using the * operator

4 * 2
8

Exponents

You can use ** as the exponent operator. An exponent is an expression of the number of times a number is muliplied by itself.

4 ** 2
16

Modulus

The modulus or remainder operator looks like this: a % b. However, it does not work as a percentage although it might look like one. Instead it divides a with b and the remainder is returned.

72 % 10
2

More mathemathical operators

These are just a few of the mathmathical operations in Python - see the table below from Python’s documentation about Built-in Types.

Click here to see more mathmathical operators

Operation

Explanation

x + y

sum of x and y

x - y

difference of x and y

x * y

product of x and y

x / y

quotient of x and y

x // y

floored quotient of x and y

x % y

remainder of x / y

-x

x negated

+x

x unchanged

abs(x)

absolute value or magnitude of x

int(x)

x converted to integer

float(x)

x converted to floating point

pow(x, y)

x to the power y

x ** y

x to the power y

Booleans

Booleans are “truth” values. They report on whether things in your Python universe are True or False. There are the only two options for a boolean: True or False. The boolean operators are or, and, and not. They are used to check if certain conditions are met before the program continues running. This is extremely helpful and even if it seems a bit confusing right now, it will make sense later. Here are a few examples of using boolean logic.

13 < 17
True

In this example above we state that 13 is less than 17 - which returns True because 13 is less than 17.

"hello" == "hi"
False

In the example above we state that ‘hello’ is equal to ‘hi’, which in the computers understanding it is not. Therefore, we get False as the output.

666 == 777
False

In this example above we state that 666 is equal to 777, which it is not. Therefore, we get False as the output.

Table of Boolean operations:

Operation

Result

x or y

if either x or y is true, then True, else False

x and y

if both x and y is true, then True, else False

not x

if x is false, then True, else False

Comparisons

You can compare values in Python using different comparison operations. Comparisons are used to compare different values and objects in Python, which we will learn much more about later. For now take a look at the comparisions and their meaning in the table underneath.

This table summarizes the comparison operations:

Comparison operation

Explanation

x < y

True if x is less than y

x <= y

True if x is less than or equal to y

x > y

True if x is greater than y

x >= y

True if x is greater than or equal to y

x == y

True if x is equal to y

!=

True if x is not equal to y


Notice the difference between a single equals sign = and a double equals sign ==

  • A double equals sign == is used as the equals operator
  • A single equals sign = is used for variable assignment (We will learn more about this in the lesson about variables)


Key Points

  • There are 4 data types in Python: Integers, floats, strings, and booleans

  • You can use the built-in function type() to find the type of a value

  • Integers are whole numbers. You can use mathemethical operations on them

  • Floats are decimal numbers. You can use mathemathical opreations on them

  • Strings are text, they can be added to one another, you can slice them to get a substring, and use the index to acess the individual character

  • Booleans are either True or False


Variables and Assignment

Overview

Teaching: 15 min
Exercises: 15 min
Questions
  • How can I store data in programs?

Objectives
  • Write scripts that assign values to variables and perform calculations with those values.

  • Correctly trace value changes in scripts that use assignment.

Use variables to store values

Variables are one of the fundamental building blocks of Python. A variable is like a tiny container where you store values and data, such as filenames, words, numbers, collections of words and numbers, and more.

The variable name will point to a value that you “assign” it. You might think about variable assignment like putting a value “into” the variable, as if the variable is a little box 🎁

(In fact, a variable is not a container as such but more like an adress label that points to a container with a given value. This difference will become relevant once we start talking about lists and mutable data types.)

You assign variables with an equals sign (=). In Python, a single equals sign = is the “assignment operator.” (A double equals sign == is the “real” equals sign.)

age = 42
first_name = 'Ahmed'

Variable names

Variable names can be as long or as short as you want, but there are certain rules you must follow.

Variables:

Use meaningful variable names

Python doesn’t care what you call variables as long as they obey the rules (alphanumeric characters and the underscore).
As you start to code, you will almost certainly be tempted to use extremely short variables names like f. Your fingers will get tired. Your coffee will wear off. You will see other people using variables like f. You’ll promise yourself that you’ll definitely remember what f means. But you probably won’t.

So, resist the temptation of bad variable names! Clear and precisely-named variables will:

flabadab = 42
ewr_422_yY = 'Ahmed'
print(ewr_422_yY, 'is', flabadab, 'years old')


Use meaningful variable names to help other people understand what the program does.
The most important “other person” is your future self!

Python is case-sensitive

Python thinks that upper- and lower-case letters are different, so Name and name are different variables. There are conventions for using upper-case letters at the start of variable names so we will use lower-case letters for now.

Off-Limits Names

The only variable names that are off-limits are names that are reserved by, or built into, the Python programming language itself — such as print, True, and list. Some of these you can overwrite into variable names (not ideal!), but Jupyter Lab (and many other environments and editors) will catch this by colour coding your variable. If your would-be variable is colour-coded green, rethink your name choice. This is not something to worry too much about. You can get the object back by resetting your kernel.

Use print() to display values

We can check to see what’s “inside” variables by running a cell with the variable’s name. This is one of the handiest features of a Jupyter notebook. Outside the Jupyter environment, you would need to use the print() function to display the variable.

first_name
Ahmed

You can run the print() function inside the Jupyter environment, too. This is sometimes useful because Jupyter will only display the last variable in a cell, while print() can display multiple variables. Additionally, Jupyter will display text with \n characters (which means “new line”), while print() will display the text appropriately formatted with new lines.

print(first_name, 'is', age, 'years old')
Ahmed is 42 years old

Variables must be created before they are used

If a variable doesn’t exist yet, or if the name has been misspelled, Python reports an error (unlike some languages, which “guess” a default value).

print(eye_color)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[1], line 1
----> 1 print(eye_color)

NameError: name 'eye_color' is not defined

The last line of an error message is usually the most informative. This message lets us know that there is no variable called eye_color in the script.

Variables Persist Between Cells

Variables defined in one cell exist in all other cells once executed, so the relative location of cells in the notebook do not matter (i.e., cells lower down can still affect those above).

  • Notice the number in the square brackets [ ] to the left of the cell.
  • These numbers indicate the order, in which the cells have been executed.
  • Cells with lower numbers will affect cells with higher numbers as Python runs the cells chronologically.
  • As a best practice, we recommend you keep your notebook in chronological order so that it is easier for the human eye to read and make sense of, as well as to avoid any errors if you close and reopen your project, and then rerun what you have done.

Remember: Notebook cells are just a way to organize a program!
As far as Python is concerned, all of the source code is one long set of instructions.

Variables can be used in calculations

age = age + 3
print('Age in three years:', age)
Age in three years: 45

This code works in the following way. We are reassigning the value of the variable age by taking its previous value (42) and adding 3, thus getting our new value of 45.

Use an index to get a single character from a string

element = 'helium'
print(element[0])
h

Use a slice to get a substring

A part of a string is called a substring. A substring can be as short as a single character. A slice is a part of a string (or, more generally, any list-like thing). We take a slice by using [start:stop], where start is replaced with the index of the first element we want and stop is replaced with the index of the element just after the last element we want. Mathematically, you might say that a slice selects [start:stop]. The difference between stop and start is the slice’s length. Taking a slice does not change the contents of the original string. Instead, the slice is a copy of part of the original string.

element = 'sodium'
print(element[0:3])
sod

Use the built-in function len() to find the length of a string

The built-in function len() is used to find the length of a string (and later, of other data types, too).

element = 'helium'
print(len(element))
6

Note that the result is 6 and not 7. This is because it is the length of the value of the variable (i.e. 'helium') that is being counted and not the name of the variable (i.e. element)

Also note that nested functions are evaluated from the inside out, just like in mathematics. Thus, Python first reads the len() function, then the print() function.

Exercises

Choosing a Name

Which is a better variable name, m, min, or minutes? Why? Hint: think about which code you would rather inherit from someone who is leaving the library:

  1. ts = m * 60 + s
  2. tot_sec = min * 60 + sec
  3. total_seconds = minutes * 60 + seconds

Solution

minutes is better because min might mean something like “minimum” (and actually does in Python, but we haven’t seen that yet).

Swapping Values

Draw a table showing the values of the variables in this program after each statement is executed. In simple terms, what do the last three lines of this program do?

x = 1.0
y = 3.0
swap = x
x = y
y = swap

Solution

swap = x  #  x->1.0 y->3.0 swap->1.0
x = y     #  x->3.0 y->3.0 swap->1.0
y = swap  #  x->3.0 y->1.0 swap->1.0

These three lines exchange the values in x and y using the swap variable for temporary storage. This is a fairly common programming idiom.

Predicting Values

What is the final value of position in the program below? (Try to predict the value without running the program, then check your prediction.)

initial = "left"
position = initial
initial = "right"

Solution

initial = "left"  # Initial is assigned the string "left"
position = initial  # Position is assigned the variable initial, currently "left"
initial = "right"  # Initial is assigned the string "right"
print(position)
left

The last assignment to position was “left”

Can you slice integers?

If you assign a = 123, what happens if you try to get the second digit of a?

Solution

Numbers are not stored in the written representation, so they can’t be treated like strings.

a = 123
print(a[1])
TypeError: 'int' object is not subscriptable

Slicing

What does the following program print?

library_name = 'social sciences'
print('library_name[1:3] is:', library_name[1:3])
  1. What does thing[low:high] do?
  2. What does thing[low:] (without a value after the colon) do?
  3. What does thing[:high] (without a value before the colon) do?
  4. What does thing[:] (just a colon) do?
  5. What does thing[number:negative-number] do?

Solution

library_name[1:3] is: oc
  1. It will slice the string, starting at the low index and ending an element before the high index
  2. It will slice the string, starting at the low index and stopping at the end of the string
  3. It will slice the string, starting at the beginning on the string, and ending an element before the high index
  4. It will print the entire string
  5. It will slice the string, starting the number index, and ending a distance of the absolute value of negative-number elements from the end of the string

Key Points

  • Use variables to store values.

  • Use meaningful variable names.

  • Python is case-sensitive.

  • Use print() to display values.

  • Variables must be created before they are used.

  • Variables persist between cells.

  • Variables can be used in calculations.

  • Use an index to get a single character from a string.

  • Use a slice to get a substring.

  • Use the built-in function len to find the length of a string.


Data Types and Type Conversion

Overview

Teaching: 15 min
Exercises: 20 min
Questions
  • What kinds of data do variables store?

  • How can I convert one type to another?

Objectives
  • Explain key differences between integers and floating point numbers.

  • Explain key differences between numbers and character strings.

  • Use built-in functions to convert between integers, floating point numbers, and strings.

Recap from lesson about Data Types

Every value has a type

Use the built-in function type to find the type of a value

We can use the built-in function type to find out what type a value has.

print(type(52))
<class 'int'>
title = 'Biochemistry'
print(type(title))
<class 'str'>

Types control what operations (or methods) can be performed on a given value

print(5 - 3)
2
print('hello' - 'h')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-67f5626a1e07> in <module>()
----> 1 print('hello' - 'h')

TypeError: unsupported operand type(s) for -: 'str' and 'str'

You can use the + and * operators on strings

full_name = 'Ahmed' + ' ' + 'Walsh'
print(full_name)
Ahmed Walsh
separator = '=' * 10
print(separator)
==========

Here, the variable “separator” is set to the value “=” (equals sign) ten times in a row.

Strings have a length (but numbers don’t)

print(len(full_name))
11
print(len(52))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-f769e8e8097d> in <module>()
----> 1 print(len(52))

TypeError: object of type 'int' has no len()

Preventing Errors: Handling numbers and strings in Python Operations

print(1 + 'A')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-fe4f54a023c6> in <module>()
----> 1 print(1 + '2')

TypeError: unsupported operand type(s) for +: 'int' and 'str'
print(1 + int('2'))
print(str(1) + '2')
3
12

Integers and floats can be mixed freely in operations

print('half is', 1 / 2.0)
print('three squared is', 3.0 ** 2)
half is 0.5
three squared is 9.0

Variables only change value when something is assigned to them

first = 1
second = 5 * first
first = 2
print('first is', first, 'and second is', second)
first is 2 and second is 5

Exercises

Fractions

What type of value is 3.4? How can you find out?

Solution

It is a floating-point number (often abbreviated “float”).

print(type(3.4))
<class 'float'>

Automatic Type Conversion

What type of value is 3.25 + 4?

Solution

It is a float: integers are automatically converted to floats as necessary.

result = 3.25 + 4
print(result, 'is', type(result))
7.25 is <class 'float'>

Choose a Type

What type of value (integer, floating point number, or character string) would you use to represent each of the following? Try to come up with more than one good answer for each problem. For example, in # 1, when would counting days with a floating point variable make more sense than using an integer?

  1. Number of days since the start of the year.
  2. Time elapsed since the start of the year.
  3. Standard book loan period.
  4. Number of reference queries in a year.
  5. Average library classes taught per semester.

Solution

  1. Integer
  2. Float
  3. Integer
  4. Integer
  5. Float

Division Types

There are three different types of division:

  1. ‘Normal’ division (aka floating-point division) is what most people may be familiar with: 5 / 2 = 2.5
  2. Floor division, which cuts out the part after the period: 5 // 2 = 2
  3. Modulo division, which only keeps the remained after division: 5 % 2 = 1

In Python 3, the / operator performs floating-point division, the // operator performs floor division, and the ‘%’ (or modulo) operator calculates the modulo division:

print('5 / 3:', 5/3)
print('5 // 3:', 5//3)
print('5 % 3:', 5%3)
5 / 3: 1.6666666666666667
5 // 3: 1
5 % 3: 2

If num_students is the number of students enrolled in a course (let say 600), and num_per_class is the number that can attend a single class (let say 42), write an expression that calculates the number of classes needed to teach everyone.

Solution

Depending on requirements it might be important to detect when the number of students per class doesn’t divide the number of students evenly. Detect it with the % operator and test if the remainder that it returns is greater than 0.

num_students = 600
num_per_class = 42
num_classes = num_students // num_per_class
remainder = num_students % num_per_class

print(num_students, 'students,', num_per_class, 'per class')
print(num_classes, 'full classes, plus an extra class with only', remainder, 'students')
600 students, 42 per class
14 full classes, plus an extra class with only 12 students

Strings to Numbers

Where reasonable, float() will convert at string or an integer to a floating point number, and int() wil convert a string or a floating point number to an integer.

print("string to float:", float("3.4"))
print("float to int:", int(3.4))
string to float: 3.4
float to int: 3

Note: conversion is some times also called typecast.

If the conversion doesn’t make sense, however, an error message will occur

print("string to float:", float("Hello world!"))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-df3b790bf0a2> in <module>()
----> 1 print("string to float:", float("Hello world!"))

ValueError: could not convert string to float: 'Hello world!'

Given this information, what do you expect the following program to do?

What does it actually do?

Why do you think it does that?

print("fractional string to int:", int("3.4"))

Solution

What do you expect this program to do? It would not be so unreasonable to expect the Python int command to convert the string “3.4” to 3.4 and an additional type conversion to 3. After all, Python performs a lot of other magic - isn’t that part of its charm?

However, Python throws an error. Why? To be consistent, possibly.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[1], line 1
----> 1 print("fractional string to int:", int("3.4"))

ValueError: invalid literal for int() with base 10: '3.4'

If you ask Python to perform two consecutive typecasts, you must convert it explicitly in code.

num_as_string = "3.4"
num_as_float = float(num_as_string)
num_as_int = int(num_as_float)
print(num_as_int)
3

We could also write it in a single line like this: int(float("3.4"))

Arithmetic with Different Types

Which of the following will print 2.0? Note: there may be more than one right answer.

first = 1.0
second = "1"
third = "1.1"
  1. first + float(second)
  2. float(second) + float(third)
  3. first + int(third)
  4. first + int(float(third))
  5. int(first) + int(float(third))
  6. 2.0 * second

Solution

Answer: 1 and 4.

  1. is correct
  2. gives 2.1
  3. gives an error because we cannot convert text to int directly
  4. is correct
  5. gives 2 (as an integer not as a float)
  6. gives an error because second is a string.

Key Points

  • Every value has a type.

  • Use the built-in function type to find the type of a value.

  • Types control what operations can be done on values.

  • Strings can be added and multiplied.

  • Strings have a length (but numbers don’t).

  • Preventing Errors: Handling numbers and strings in Python operations.

  • Integers and floats can be mixed freely in operations.

  • Variables only change value when something is assigned to them.


Built-in Functions and Help

Overview

Teaching: 25 min
Exercises: 15 min
Questions
  • How can I use built-in functions?

  • How can I find out what they do?

  • What kind of errors can occur in programs?

Objectives
  • Explain the purpose of functions.

  • Correctly call built-in Python functions.

  • Use help to display documentation for built-in functions.

  • Correctly describe situations in which SyntaxError and NameError occur.

Use comments to add documentation to programs

When coding, it is always a good idea to write comments explaining what the code does - and why.
Comments will help other people understand what the program does.
Just like we spoke about in regards to meaningful variable names, the most important “other person” is your future self!

# This sentence isn't executed by Python.
name = 'Python for Absolute Beginners'   # Neither is this comment - anything after '#' is ignored.

A function may take zero or more arguments

We have seen some functions already (like print() and type()) — now let’s take a closer look.

print('before')
print()
print('after')
before

after

Commonly-used built-in functions include max, min, and round

print(max(1, 2, 3))
print(min('a', 'b', 'c'))
print(min('a', 'A'))
3
a
A


To see more built-in functions, visit the Python Documentation

Functions may only work for certain (combinations of) arguments

print(max(1, 'a'))
TypeError: '>' not supported between instances of 'str' and 'int'


The error message tells us, that we cannot compare strings and integers.

Functions may have default values for some arguments

round(3.712)
4
round(3.712, 1)
3.7

Use the built-in function help to get help for a function

help(round)
Help on built-in function round in module builtins:

round(...)
    round(number[, ndigits]) -> number

    Round a number to a given precision in decimal digits (default 0 digits).
    This returns an int when called with one argument, otherwise the
    same type as the number. ndigits may be negative.

Python reports a syntax error when grammar rules (that’s Python grammar, not English grammar) have been violated

You’ve seen errors when you try to use a function incorrectly, but you can also have errors when you use punctuation incorrectly.

# Forgot to close the quotation marks around the string.
name = 'Feng
    name = 'Feng
           ^
SyntaxError: unterminated string literal
# An extra '=' in the assignment.
age = = 52
    age = = 52
          ^
SyntaxError: invalid syntax
print("hello world"
  Cell In[1], line 1
    print("hello world"
                       ^
SyntaxError: incomplete input

Python reports a runtime error when something goes wrong while a program is executing

In Python, a runtime error is an error that occurs while a Python program is running. These errors are also known as exceptions. Runtime errors in Python are typically caused by unexpected conditions or events that disrupt the normal flow of the program.
They can happen for various reasons, for example:

age = 53
remaining = 100 - aege # mis-spelled 'age'
NameError: name 'aege' is not defined

Every function returns something

result = print('example')
print('result of print is', result)
example
result of print is None

Contrary to what we might expect, print does not return any value as such. I carries out the execution (i.e., it prints), but after that nothing is returned. Thus, it has a return value of None.

Exercises

What Happens When

  1. Explain in simple terms the order of operations in the following program: when does the addition happen, when does the subtraction happen, when is each function called, etc.
  2. What is the final value of word?
word = 'blah '
word = max(min(word * 2 + 'blur ', 'aaah '), 'ping')
print(word)

Solution

ping
  1. Initialization: word is assigned the initial value ‘blah ‘.
  2. Inside max() function:
    • word * 2 results in ‘blah blah ‘. (Repeats the string ‘blah ‘ twice using *.)
    • ‘blah blah ‘ + ‘blur ‘ results in ‘blah blah blur ‘. (Concatenates the two strings using +.)
    • ‘aaah ‘ is compared with ‘blah blah blur ‘. The min() function returns the smaller of the two strings, which is ‘aaah ‘.
  3. Outer max() function:
    • The result of the min() function (‘aaah ‘) is passed as an argument.
    • The max() function then compares ‘aaah ‘ with ‘ping’ and returns the larger of the two strings, which is ‘ping’.
  4. Assignment: Finally, the value ‘ping’ is assigned to the variable word.
  5. Output: The program prints the value of word, which is ‘ping’.

Spot the Difference

  1. Predict what each of the print statements in the program below will print.
  2. Does max(len(rich), poor) run or produce an error message? If it runs, does its result make sense to you? (Remember that we are comparing the value of the variable and not the name of the variable.)
rich = "gold"
poor = "tin"
print(max(rich, poor))
print(max(len(rich), len(poor)))

Solution

tin
4

Why Not?

Why don’t max and min return None when they are given no arguments?

Solution

Both functions require at least one argument to execute.

print(max())
TypeError: max expected at least 1 argument, got 0

Last Character of a String

If Python starts counting from zero, and len returns the number of characters in a string, what index expression will get the last character in the string name? (Note: we will see a simpler way to do this in a later episode.)

Solution

name[len(name) - 1]

Key Points

  • Use comments to add documentation to programs.

  • A function may take zero or more arguments.

  • Commonly-used built-in functions include max, min, and round.

  • Functions may only work for certain (combinations of) arguments.

  • Functions may have default values for some arguments.

  • Use the built-in function help to get help for a function.

  • Every function returns something.

  • Python reports a syntax error when it can’t understand the source of a program.

  • Python reports a runtime error when something goes wrong while a program is executing.


Lists

Overview

Teaching: 20 min
Exercises: 20 min
Questions
  • How can I store multiple items?

Objectives
  • Explain why programs need collections of items.

  • Write programs that create lists, index them, slice them, and modify them through assignment and method calls.

A list stores many items in a single structure

Scenario: You have set up an thermometer to do temperature measurements in a storage room for rare books.

temperatures = [17.3, 17.5, 17.7, 17.5, 17.6]
print('temperatures:', temperatures)
print('length:', len(temperatures))
temperatures: [17.3, 17.5, 17.7, 17.5, 17.6]
length: 5

Use an item’s index to fetch it from a list

print('zeroth item of temperatures:', temperatures[0])
print('fourth item of temperatures:', temperatures[4])
zeroth item of temperatures: 17.3
fourth item of temperatures: 17.6

Slice

print(temperatures)
print(temperatures[1:4])
[17.3, 17.5, 17.7, 17.5, 17.6]
[17.5, 17.7, 17.5]

Lists’ items can be replaced by assigning to them

Use an index expression on the left of the assignment operator (=) to replace a value:

temperatures[0] = 16.5
print('temperatures is now:', temperatures)
temperatures is now: [16.5, 17.5, 17.7, 17.5, 17.6]

Appending items to a list lengthens it

Use list_name.append to add items to the end of a list:

print('temperatures is initially:', temperatures)
temperatures.append(17.9)
temperatures.append(18.2)
print('temperatures has become:', temperatures)
temperatures is initially: [16.5, 17.5, 17.7, 17.5, 17.6]
temperatures has become: [16.5, 17.5, 17.7, 17.5, 17.6, 17.9, 18.2]

Table of list methods

For more in-depth information, see the Python Documentation.

Method Description
append() Adds an element at the end of the list
clear() Removes all the elements from the list
copy() Returns a copy of the list
count() Returns the number of elements with the specified value
extend() Add the elements of a list (or any iterable), to the end of the current list
index() Returns the index of the first element with the specified value
insert() Adds an element at the specified position
max() Calculates the maximum of all the elements of the list
min() Calculates the minimum of all the elements of the list
pop() Removes the element at the specified position
remove() Removes the first item with the specified value
reverse() Reverses the order of the list
sort() Sorts the list

Use del to remove items from a list entirely

numbers = [2, 3, 5, 7, 11]
print('numbers before removing last item:', numbers)
del numbers[4]
print('numbers after removing last item:', numbers)
numbers before removing last item: [2, 3, 5, 7, 11]
numbers after removing last item: [2, 3, 5, 7]

The empty list contains no items

Lists may contain items of different types

A single list may contain numbers, strings, and anything else.

goals = [1, 'Create lists.', 2, 'Extract items from lists.', 3, 'Modify lists.']
print(goals)
[1, 'Create lists.', 2, 'Extract items from lists.', 3, 'Modify lists.']

Lists are mutable

In Python, mutable data types, such as lists, are data structures that can be modified or changed after they are created. This means you can add, remove, or modify elements within a list without creating a new list.

For example, you can append new items, insert items at specific positions, remove items, and change the values of existing items in a list. This behavior contrasts with immutable data types, like integers, floats, and strings, where once created, their contents cannot be altered without creating a new object. (This was briefly mentioned in the lesson about Variables and Assignment.)

Character strings are immutable

Remember that you can get single characters from a character string using indexes in square brackets:

element = 'carbon'
print('zeroth character:', element[0])
print('third character:', element[3])
zeroth character: c
third character: b


But!

element[0] = 'C'
TypeError: 'str' object does not support item assignment


Notice the difference between overwriting and changing values

In Python, when you use the assignment operator (=) with a variable (and not a variable index!), it doesn’t change the original value of the variable. Instead, it replaces the current value of the variable with the new value on the right-hand side of the assignment.

element = 'carbon'
print(element)
element = 'helium'
print(element)
carbon
helium

In the code above, the variable element initially holds the value ‘carbon’, but when the second line is executed, it is overwritten with the new value ‘helium’. The old value ‘carbon’ is effectively discarded, and element now contains ‘helium’.

In contrast, when assigning to a list index:

elements = ['carbon', 'helium']
print(elements)
elements[0] = 'hydrogen'
print(elements)
['carbon', 'helium']
['hydrogen', 'helium']

We don’t overwrite the variable elements but rather we change the content of the zeroth index.
Thus, the difference between immutable and mutable data types.

Indexing beyond the end of the collection is an error

print('99th element of element is:', element[99])
IndexError: string index out of range

Exercises

Fill in the Blanks

Fill in the blanks so that the program below produces the output shown.

values = ____
values.____(1)
values.____(3)
values.____(5)
print('first time:', values)
values = values[____]
print('second time:', values)
first time: [1, 3, 5]
second time: [3, 5]

Solution

values = []
values.append(1)
values.append(3)
values.append(5)
print('first time:', values)
values = values[1:3]
print('second time:', values)
first time: [1, 3, 5]
second time: [3, 5]

How Large is a Slice?

If ‘low’ and ‘high’ are both non-negative integers, how long is the list values[low:high]?

Solution

The list’s length would be equal to high - low.

From Strings to Lists and Back

Given this:

print('string to list:', list('tin'))
print('list to string:', ''.join(['g', 'o', 'l', 'd']))
print('list to string:', '-'.join(['g', 'o', 'l', 'd']))
string to list: ['t', 'i', 'n']
list to string: gold
list to string: g-o-l-d
  1. Explain in simple terms what list('some string') does.
  2. What does '-'.join(['x', 'y']) generate?

Solution

  1. It creates a list of the some strings characters as elements.
  2. It creates a string composed of x and y, separated by a hyphen character(-).

Working With the End

What does the following program print?

element = 'helium'
print(element[-1])
  1. How does Python interpret a negative index?
  2. If a list or string has N elements, what is the most negative index that can safely be used with it, and what location does that index represent?
  3. If values is a list, what does del values[-1] do?
  4. How can you display all elements but the last one without changing values? (Hint: you will need to combine slicing and negative indexing.)

Solution

m
  1. A negative index begins at the final element.
  2. -(N) corresponds to the first index, which is the [0] index.
  3. It removes the final element of the list.
  4. You could do the following: print(values[0:-1])

Stepping Through a List

What does the following program print?

element = 'fluorine'
print(element[::2])
print(element[::-1])
  1. If we write a slice as low:high:stride, what does stride do?
  2. What expression would select all of the even-numbered items from a collection?

Solution

furn
eniroulf
  1. stride indicates both the number of steps, and from which end: positive starts from first element, negative from the last element.
  2. element[1::2]

Slice Bounds

What does the following program print?

element = 'lithium'
print(element[0:20])
print(element[-1:3])

Solution

lithium 
''

There is no 20th index, so the entire string is captured.
There is no element after the -1 index.

Sort and Sorted

What do these two programs print? In simple terms, explain the difference between sorted(letters) and letters.sort().

# Program A
letters = list('gold')
result = sorted(letters)
print('letters is', letters, 'and result is', result)
# Program B
letters = list('gold')
result = letters.sort()
print('letters is', letters, 'and result is', result)

Solution

Program A:

letters is ['g', 'o', 'l', 'd'] and result is ['d', 'g', 'l', 'o']

Program B:

letters is ['d', 'g', 'l', 'o'] and result is None

sorted(letters) returns a sorted copy of the list without changing the original list, while letters.sort() sorts the original list but does not return anything, i.e. returns None.

Copying (or Not)

What do these two programs print? In simple terms, explain the difference between new = old and new = old[:].

# Program A
old = list('gold')
new = old      # simple assignment
new[0] = 'D'
print('new is', new, 'and old is', old)
# Program B
old = list('gold')
new = old[:]   # assigning a slice
new[0] = 'D'
print('new is', new, 'and old is', old)

Solution

Program A:

new is ['D', 'o', 'l', 'd'] and old is ['D', 'o', 'l', 'd']

Program B:

new is ['D', 'o', 'l', 'd'] and old is ['g', 'o', 'l', 'd']

new = old is assigning old to new. This means that the two variables both point to the same value. Thus, changing the contents of either variable will affect the other. In contrast, new = old[:] is a slice assignment, which will only return a copy of old.

Key Points

  • A list stores many items in a single structure.

  • Use an item’s index to fetch it from a list.

  • Lists’ items can be replaced by assigning to them.

  • Appending items to a list lengthens it.

  • Use del to remove items from a list entirely.

  • The empty list contains no items.

  • Lists may contain items of different types.

  • Lists are mutable.

  • Indexing beyond the end of the collection is an error.


For Loops

Overview

Teaching: 20 min
Exercises: 20 min
Questions
  • How can I make a program repeat a task?

Objectives
  • Explain what for loops are normally used for.

  • Trace the execution of a simple (unnested) loop and correctly state the values of variables in each iteration.

  • Write for loops that use accumulator values.

A for loop executes commands once for each value in a collection

for number in [2, 3, 5]:
    print(number)
print(2)
print(3)
print(5)
2
3
5

The first line of the for loop must end with a colon, and the body must be indented

for number in [2, 3, 5]:
print(number)
    print(number)
    ^
IndentationError: expected an indented block after 'for' statement on line 1
firstName = "Jon"
  lastName = "Smith"
    lastName = "Smith"
    ^
IndentationError: unexpected indent

A for loop is made up of a collection, a loop variable, and a body

for number in [2, 3, 5]:
    print(number)

Loop variable names follow the normal variable name conventions

The body of a loop can contain many statements

numbers = [2, 3, 5]
for n in numbers:
    squared = n ** 2
    cubed = n ** 3
    print("The number", n, "squared is:", squared, ", and the number", n, "cubed is:", cubed)
The number 2 squared is: 4 , and the number 2 cubed is: 8
The number 3 squared is: 9 , and the number 3 cubed is: 27
The number 5 squared is: 25 , and the number 5 cubed is: 125

Use range to go through a sequence of numbers

print('A range is not a list: range(0, 3)')
for number in range(0, 3):
    print(number)
A range is not a list: range(0, 3)
0
1
2

Or use range to repeat an action a set number of times

for number in range(5):
    print("Again!")
Again!
Again!
Again!
Again!
Again!

Using accumulator variables

# Sum all of the integers from 1 to 10.
total = 0
for number in range(10):
   total = total + (number + 1)
print(total)
55

Exercises

Classifying Errors

Is an indentation error a syntax error or a runtime error?

Solution

It is a syntax error. The problem has to do with the placement of the code, not its logic.

Tracing Execution

Create a table showing the numbers of the lines that are executed when this program runs, and the values of the variables after each line is executed.

total = 0
for animal in ['cat', 'dog', 'elephant', 'fish']:
    total = total + 1

Solution

Code line # total animal
1 0 N/A
2 0 'cat'
3 1 'cat'
2 1 'dog'
3 2 'dog'
2 2 'elephant'
3 3 'elephant'
2 3 'fish'
3 4 'fish'

Explanation:

  • Line 1 initializes the variable total with a value of 0.
  • Line 2 begins a for loop that iterates over the list ['cat', 'dog', 'elephant', 'fish'].
    • Line 2 is the first iteration, where animal takes the value ‘cat’, and total retains 0.
    • Line 3 increments total by 1, making it 1, and animal retains the value ‘cat’.
    • Line 2 is the second iteration, where animal takes the value ‘dog’, and total retains 1.
    • Line 3 increments total by 1, making it 2, and animal retains the value ‘dog’.
    • Line 2 is the third iteration, where animal takes the value ‘elephant’, and total retains 2.
    • Line 3 increments total by 1, making it 3, and animal retains the value ‘elephant’.
    • Line 2 is the fourth iteration, where animal takes the value ‘fish’, and total retains 3.
    • Line 3 increments total by 1, making it 4, and animal retains the value ‘fish’.

After the program finishes, total is 4, and animal retains its value from the last iteration, which is ‘fish’.

Reversing a String

Fill in the blanks in the program below so that it prints “nit” (the reverse of the original character string “tin”).

original = "tin"
result = ____
for char in original:
    result = ____
print(result)

Solution

  • result is an empty string because we use it to build or accumulate on our reverse string.
  • char is the loop variable for original.
  • For each iteration of the loop, char takes on one value (character) from original.
  • Add char to the beginning of result to change the order of the string.
  • Our loop code should look like this:
original = "tin"
result = ""
for char in original:
   result = char + result
print(result)

If you were to explain the loop step by step, the iterations would look something like this:

#First loop
char = "t"
result = ""
char + result = "t"
#Second loop
char = "i"
result = "t"
char + result = "it"
#Third loop
char = "n"
result = "it"
char + result = "nit"

Practice Accumulating

Fill in the blanks in each of the programs below to produce the indicated result.

# Total length of the strings in the list: ["red", "green", "blue"] => 12
total = 0
for word in ["red", "green", "blue"]:
    ____ = ____ + len(word)
print(total)

Solution

# Total length of the strings in the list: ["red", "green", "blue"] => 12
total = 0
for word in ["red", "green", "blue"]:
    total = total + len(word)
print(total)
# List of word lengths: ["red", "green", "blue"] => [3, 5, 4]
lengths = ____
for word in ["red", "green", "blue"]:
    lengths.____(____)
print(lengths)

Solution

# List of word lengths: ["red", "green", "blue"] => [3, 5, 4]
lengths = []
for word in ["red", "green", "blue"]:
    lengths.append(len(word))
print(lengths)
# Concatenate all words: ["red", "green", "blue"] => "redgreenblue"
words = ["red", "green", "blue"]
result = ____
for ____ in ____:
    ____
print(result)

Solution

# Concatenate all words: ["red", "green", "blue"] => "redgreenblue"
words = ["red", "green", "blue"]
result = ""
for word in words:
    result = result + word
print(result)
# Create acronym: ["red", "green", "blue"] => "rgb"
# write the whole thing

Solution

acronym = ''
colours = ["red", "green", "blue"]
for colour in colours:
    acronym = acronym + colour[0]
print(acronym)

Cumulative Sum

Reorder and properly indent the lines of code below so that they print an array with the cumulative sum of data. The result should be [1, 3, 5, 10].

cumulative += [sum]
for number in data:
cumulative = []
sum += number
print(cumulative)
sum = 0
data = [1,2,2,5]

Solution

data = [1,2,2,5]
cumulative = []
sum = 0
for number in data:
  sum += number
  cumulative += [sum]
print(cumulative)
[1, 3, 5, 10]

Identifying Variable Name Errors

  1. Read the code below and try to identify what the errors are without running it.
  2. Run the code and read the error message. What type of NameError do you think this is? Is it a string with no quotes, a misspelled variable, or a variable that should have been defined but was not?
  3. Fix the error.
  4. Repeat steps 2 and 3, until you have fixed all the errors.
for number in range(10):
    # use a if the number is a multiple of 3, otherwise use b
    if (Number % 3) == 0:
        message = message + a
    else:
        message = message + "b"
print(message)

Identifying Item Errors

  1. Read the code below and try to identify what the errors are without running it.
  2. Run the code, and read the error message. What type of error is it?
  3. Fix the error.
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
print('My favorite season is ', seasons[4])

Solution

It is an index error:

IndexError: list index out of range

The problem is that 4 points to an item that doesn’t exist in the list. Remember the first item of a list in Python is 0.
Replace seasons[4] with seasons[0], seasons[1], seasons[2] or seasons[3] to have the different items of the list printed.

Key Points

  • A for loop executes commands once for each value in a collection.

  • The first line of the for loop must end with a colon, and the body must be indented.

  • Indentation is always meaningful in Python.

  • A for loop is made up of a collection, a loop variable, and a body.

  • Loop variables can be called anything (but it is strongly advised to have a meaningful name to the looping variable).

  • The body of a loop can contain many statements.

  • Use range to iterate over a sequence of numbers.


Conditionals

Overview

Teaching: 25 min
Exercises: 20 min
Questions
  • How can you use conditional statements to control program flow?

Objectives
  • Explain the use of if and else statements and simple Boolean expressions.

  • Explain the use of while statements.

  • Trace the execution of unnested conditionals and conditionals inside loops.

Use if statements to control whether or not a block of code is executed

mass = 3.54
if mass > 3.0:
    print(mass, 'is larger than 3.0')

mass = 2.07
if mass > 3.0:
    print (mass, 'is larger than 3.0')
3.54 is larger than 3.0

Conditionals are often used inside loops

masses = [3.54, 2.07, 9.22, 1.86, 1.71]
for m in masses:
    if m > 3.0:
        print(m, 'is larger than 3.0')
3.54 is larger than 3.0
9.22 is larger than 3.0

Use else to execute a block of code when an if condition is not true

masses = [3.54, 2.07, 9.22, 1.86, 1.71]
for mass in masses:
    if mass > 3.0:
        print(mass, 'is larger than 3.0')
    else:
        print(mass, 'is smaller than 3.0')
3.54 is larger than 3.0
2.07 is smaller than 3.0
9.22 is larger than 3.0
1.86 is smaller than 3.0
1.71 is smaller than 3.0

Use elif to specify additional tests

masses = [3.54, 2.07, 9.22, 1.86, 1.71]
for mass in masses:
    if mass > 9.0:
        print(mass, 'is HUGE')
    elif mass > 3.0:
        print(mass, 'is larger')
    else:
        print(mass, 'is smaller')
3.54 is larger
2.07 is smaller
9.22 is HUGE
1.86 is smaller
1.71 is smaller

Conditions are tested once, in order

points = 85
if points >= 70:
    print('grade is C')
elif points >= 80:
    print('grade is B')
elif points >= 90:
    print('grade is A')
grade is C
points = 85
if points >= 90:
    print('grade is A')
elif points >= 80:
    print('grade is B')
elif points >= 70:
    print('grade is C')
grade is B


speed = 10.0
if speed > 20.0:
    print('moving too fast')
else:
    print('adjusting speed')
    speed = 50.0
adjusting speed
speed = 10.0
for i in range(5): # execute the loop 5 times
    print(i, ':', speed)
    if speed > 20.0:
        print('moving too fast')
        speed = speed - 5.0
    else:
        print('moving too slow')
        speed = speed + 10.0
print('final speed:', speed)
0 : 10.0
moving too slow
1 : 20.0
moving too slow
2 : 30.0
moving too fast
3 : 25.0
moving too fast
4 : 20.0
moving too slow
final speed: 30.0


Compound statements; using and, or, and parentheses

  • Often, you want some combination of things to be true.
  • You can combine relations within a conditional using and and/or or.
  • This is called compound statements.
  • Continuing the example above, suppose you have:
mass     = [ 3.54,  2.07,  9.22,  1.86,  1.71]
speed    = [10.00, 20.00, 30.00, 25.00, 20.00]

for i in range(5):
    if mass[i] > 5 and speed[i] > 20:
        print("Fast heavy object. Duck!")
    elif mass[i] > 2 and mass[i] <= 5 and speed[i] <= 20:
        print("Normal traffic")
    elif mass[i] <= 2 and speed[i] <= 20:
        print("Slow light object. Ignore it.")
    else:
        print("Whoa! Something is up with the data. Check it.")
  • Just like with arithmetic, you can and should use parentheses whenever there is possible ambiguity.
  • If no parentheses are used, Python will read code based on operator precedence.
  • However, a good general rule is to always use parentheses when mixing and and or in the same condition.
  • That is, instead of:
if mass[i] <= 2 or mass[i] >= 5 and speed[i] > 20:

You should write it like one of these two so it is perfectly clear to a reader (and to Python) what you really mean:

if (mass[i] < 2 or mass[i] > 5) and speed[i] > 20:
if mass[i] < 2 or (mass[i] > 5 and speed[i] > 20):
  • Notice that the two statements above test for something different!
  • The first statement requires mass to be outside the range of 2 to 5 and the speed to be greater than 20.
  • The second statement requires either of these two to be true:
    1. mass must be smaller than 2, or
    2. mass must be greater than 5 and speed must be greater than 20.

While loops

In Python, a while loop allows you to repeatedly execute a block of code as long as a certain condition is true. This can be useful when you want to perform an action multiple times until a specific condition is met.

The while syntax

The basic structure of a while loop in Python is as follows:

while condition:
    # Code to be executed as long as the condition is true
count = 1
while count <= 5:
    print(count)
    count += 1
1
2
3
4
5

Infinite loops

i = 0
while True:
    print(i)
    i += 1
i = 0
while i <= 100:
    print(i)
    i += 1

Exercises:

Tracing Execution

What does this program print?

pressure = 71.9
if pressure > 50.0:
    pressure = 25.0
elif pressure <= 50.0:
    pressure = 0.0
print(pressure)

Solution

25.0

Trimming Values

Fill in the blanks so that this program creates a new list containing zeroes (0) where the original list’s values were negative and ones (1) where the original list’s values were zero or positive.

original = [-1.5, 0.2, 0.4, 0.0, -1.3, 0.4]
result = ____
for value in original:
    if ____:
        result.append(0)
    else:
        ____
print(result)
[0, 1, 1, 1, 0, 1]

Solution

original = [-1.5, 0.2, 0.4, 0.0, -1.3, 0.4]
result = []
for value in original:
   if value < 0:
       result.append(0)
   else:
      result.append(1)
print(result)

Using the input() function

  • Try out the code below.
  • What does the script do?
  • What does the function input() do?
user_input = ""
while user_input != "quit":
  user_input = input("Enter 'quit' to exit: ")

Solution

  • This loop continuously asks the user for input until they type “quit.”
  • It checks the value of user_input in each iteration.

The Number Guessing Game with hints

In this final exercise, we will write a Python program for a number guessing game!

This exercise builds on the knowledge you have gathered in this course up till now.
Try to solve it without looking at the solution.

Take it easy, don’t sweat it, and have fun writing your first real Python script!

The program should do the following:

  1. Generate a random secret number between 1 and 20.
  2. Ask the user to guess the secret number.
  3. Provide hints to the user based on their guess:
    • If the guess is correct, print “Congratulations! You guessed the correct number.”
    • If the guess is too low, print “Too low. Try again.”
    • If the guess is too high, print “Too high. Try again.”
  4. Allow the user to keep guessing until they correctly guess the number.
  5. Count and display the number of attempts it took for the user to guess correctly.

Requirements:

  • Use a while loop to repeatedly ask the user for their guess until they guess correctly.
  • Use if, elif, and else statements to provide appropriate hints based on the user’s guess.

Hints:

  • You will need to use the input() function introduced in the exercise above.
  • You can use the random module to generate the secret number. Here’s an example of how to import and use it:
import random

# Generate a random secret number between 1 and 20
secret_number = random.randint(1, 20)

Sample Output (simplified):

You will need your output to look something like this:

Welcome to the Number Guessing Game!

Guess the secret number (1-20): 10
Too low. Try again.

Guess the secret number (1-20): 15
Too high. Try again.

Guess the secret number (1-20): 12
Congratulations! You guessed the correct number in 3 attempts.

Solution

Are you really sure, you want to see the solution yet?
Only look if you have solved it yourself.
Remember:

Python pain is temporary, pride is forever!

“Yes, I am weak and I want to see the solution!”

import random

# Generate a random secret number between 1 and 20
secret_number = random.randint(1, 20)

# Initialize variables
attempts = 0
guessed_correctly = False

print("Welcome to the Number Guessing Game!")

while not guessed_correctly:
    # Ask the user to guess the secret number
    user_guess = int(input("Guess the secret number (1-20): "))
    
    # Increment the attempts counter
    attempts = attempts + 1

    # Check if the guess is correct, too low, or too high
    if user_guess == secret_number:
        guessed_correctly = True
        print("Congratulations! You guessed the correct number in", attempts, "attempts.")
    elif user_guess < secret_number:
        print("Too low. Try again.")
    else:
        print("Too high. Try again.")

Key Points

  • Use if statements to control whether or not a block of code is executed.

  • Conditionals are often used inside loops.

  • Use else to execute a block of code when an if condition is not true.

  • Use elif to specify additional tests.

  • Conditions are tested once, in order.

  • A while loop allows you to repeatedly execute a block of code as long as a certain condition is true.


Evaluation

Overview

Teaching: 0 min
Exercises: 5 min
Questions
  • Please complete the evaluation!

Objectives
  • Help us make the course better.

Please complete the evaluation

We would greatly appreciate if you, after the course, would kindly spend 2-5 minutes filling out this questionnaire:

http://bit.ly/KUB2023

We appreciate your honest opinions!

Thank you!

Key Points