Building Blocks#

We start our quick run through Python with essential features which can be found in almost every high-level programming language. What we will meet here is known as structured programming. Later on we will move on to object oriented programming.

Comments#

A Python source code file may contain text ignored by the Python interpreter. Such comments help to understand and document the source code. Everything following a # symbol is ignored by the interpreter.

a = 1    # here we could place some explanation

# this whole line is a comment and completely ignored by the interpreter
b = 2

For the Python interpreter the above code is equivalent to

a = 1
b = 2

Note that empty lines do not matter. We may place empty lines everywhere like comments to make the code more readable.

Assignments#

Data (numbers, strings and other) in memory can be associated to a human readable string. Such a combination of a piece of data and a name for it is known as variable. To assign a name to a piece of data Python uses the = sign.

a = 1

The above code writes the number 1 to some location in memory and assigns the name a to it. Whenever we want to use or modify this value we simply have to provide its name a. The Python interpreter translates the name into a memory address.

print(a)
1

This prints the value of the variable a to screen.

Simple Data Types#

We have to distiguish different types of data because each type comes with its own set of operations. Numbers can be added and multiplied, for example, whereas strings can be concatenated but not multiplied. In Python we do not have to care too much about choosing the correct data type, because the interpreter does much of the technical stuff (e.g., how much memory is required?) for us.

a = 2           # an integer
b = 2.1         # a floating point number
c = "Hello!"    # a string
d = True        # a boolean value

print(a)
print(b)
print(c)
print(d)
2
2.1
Hello!
True

Integers#

Integers are the numbers …, -2, -1, 0, 1, 2,….

Note

In most programming languages there is a maxmimum value an integer can attain, like \(-2^{31},...,2^{31}+1\). In Python there is no limit on the size of an integer.

a = 5 + 2     # addition
b = 5 - 2     # substraction
c = 5 * 2     # multiplication
d = 5 // 2    # floor division
e = 5 % 2     # remainder of devision
f = 5 / 2     # division (yields a floating point number)
g = 2 ** 5    # power

print(a)
print(b)
print(c)
print(d)
print(e)
print(f)
print(g)
7
3
10
2
1
2.5
32

Undefined operations will be identified by the interpreter.

a = 1 // 0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 a = 1 // 0

ZeroDivisionError: integer division or modulo by zero

If we want the user to input an integer, we may use the following code

a = int(input("Give me an integer: "))
print(a)

Like print and input also int is a function. It takes a string and converts it to an integer. If this is not possible, an error message appears and program execution is stopped.

Floating Point Numbers#

Python supports floating point numbers (also known as floats) in the approximate range 1e-308…1e+308 with 15 significant decimal places (double precision in IEEE 754 standard). Floating point numbers are stored as a pair of coefficient and exponent of 2, where both coefficient and exponent are integers.

Example: \(0.1875=3\cdot 2^{-4}\) with coefficient 3 and exponent -4.

Important

Most decimal fractions cannot be represented exactly as float, which may cause tiny errors in computations.

Example:

\[\begin{align*} 0.1&\approx 3602879701896397\cdot 2^{-55}\\ &=0.1000000000000000055511151231257827021181583404541015625 \end{align*}\]

See Python documentation for more detailed explanation and additional examples.

a = 5        # integer (stored as is)
b = 5.0      # float (stored as coefficient and exponent) 
c = 5.123    # float
d = c + 2    # float plus integer yields float

print(a)
print(b)
print(c)
print(d)
5
5.0
5.123
7.123

Note that Python converts data types automatically as needed. Destination type is chosen to prevent loss of data as far as possible (cf. line 4 in the code example above). If conversion is not possible, the interpreter will complain about.

Strings#

In Python strings are as simple as numbers. Just enclose some characters in single or double quotation marks and they will become a Python string.

a = 'Hello'      # single quotation marks
b = 'my'
c = "friend!"    # double quotation marks

# strings may be concatenated using +
d = a + ' ' + b + ' ' + c

print(d)
Hello my friend!

Behavior of operators like + depends on the data type of the operands. Adding two integers 123 + 456 yields the integer 579. Adding two strings '123' + '456' yields the string '123456'.

If a string contains single quotation marks, then use double quotation marks and vice versa. Alternatively, you may escape quotation marks in a string with a backslash.

a = "He isn't cool."
b = 'He isn\'t cool.'
c = 'He said: "Your are crazy"'
d = "He said: \"Your are crazy\""

print(a)
print(b)
print(c)
print(d)
He isn't cool.
He isn't cool.
He said: "Your are crazy"
He said: "Your are crazy"

Boolean Values#

Boolean values or truth values can hold either True or False. Typically, they are the result of comparisons. Boolean values support logical operations like and, or, and not (see Logic).

a = True
b = a and False
c = not a
d = a or b

print(a)
print(b)
print(c)
print(d)
True
False
False
True

Functions#

A function is a piece of Python code with a name. To execute the code we have to write its name, optionally followed by parameters (sometimes denoted as arguments) influencing the function’s code execution. After executing the function some value can be returned to the caller.

This concept is required in two circumstances:

  • a piece of code is needed several times,

  • readability shall be increased by hiding some code.

Built-in Functions#

Python has several built-in functions, like print and input. The print function takes one or more variables and prints them on screen. In case of multiple arguments outputs are separated by spaces. The input function may be called without arguments. It waits for user input and returns the input to the calling code.

a = input()
print('You typed:', a)

Above we also met the int function, which converts a string to an integer if possible. The int function behaves exactly in the same way as all other functions, but it is not a built-in function in the stricter sense. Instead, it’s the constructor of a class, a concept we’ll discuss later on.

Keyword Arguments#

Functions accept different kinds of arguments. Some are passed as they are (like for print). Those are called positional arguments and we meet them in almost all programming languages.

In Python often we’ll see function calls of the form some_function(argument_name=passed_value). Such arguments are called keyword arguments and help to increase code readability. If a function accepts multiple keyword arguments, we do not have to care about which one to pass first, second and so on. Details will be discussed in a separate chapter on functions later on.

Function Definitions#

We can define new functions with the def keyword.

def say_hello(name):
    ''' Print a hello message. '''

    message = 'Hello ' + name + '!'
    print(message)

    
say_hello('John')
say_hello('Anna')
Hello John!
Hello Anna!

Note the indentation of the function’s code and the docstring '''...'''. The indentation tells the Python interpreter which lines of code belong to the function. The docstring is ignored by the interpreter like a comment. But tools for automatic generation of software documentation extract the docstring and process it.

To return a value (like input does) we would have to add a line containing return my_value. The return keyword stops execution of the function and returns control to the calling code. We place return wherever appropriate for our purposes. Often, but not always, it’s in the last line of the function’s code.

Important

Variables introduced inside a function, like message above, are only accessible inside that function. But variables defined outside a function are accessible inside functions, too. It’s considered good practice to keep inside and outside variables separated. That is, don’t use outside variables inside a function. Instead pass all values required by the function as arguments and return results required outside a function with return. Exceptions prove the rule.

Errors in Functions#

If there is an error in a function’s code, the Python interpreter will show an error message together with a traceback. That’s a list of code lines leading to the erroneous line. If a program calls a function which again calls a function which contains an error, the traceback will have three entries.

In the following example the variable name is incorrect in the print line.

def say_hello(name):
    ''' Print a hello message. '''

    message = 'Hello ' + name + '!'
    print(mesage)

    
say_hello('John')
say_hello('Anna')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [15], in <cell line: 8>()
      4     message = 'Hello ' + name + '!'
      5     print(mesage)
----> 8 say_hello('John')
      9 say_hello('Anna')

Input In [15], in say_hello(name)
      2 ''' Print a hello message. '''
      4 message = 'Hello ' + name + '!'
----> 5 print(mesage)

NameError: name 'mesage' is not defined

If there would be an error in print (because you passed an unexpected argument, for instance), then the traceback would have an additional entry showing the erroneous line in the definition of print.

Hint

Tracebacks may become very long if your code implies a problem in some built-in or library function. Check the traceback carefully to find the last entry referring to your code. That’s the most likely location of the problem’s cause.

Conditional Execution#

Up to now program flow is linear. There is one path and the interpreter will follow this path. Here comes the first element of flow control: conditional execution.

a = int(input('Give me a number: '))
b = int(input('Give me another number: '))

if a > b:
    print('First number is greater.')
else:
    print('First number is not greater.')

If the condition is satisfied, then the first code block is executed. If it is not satisfied, the else block is executed. For equality use ==, for inequality use !=. Other comparison operators are <, >, <=, >=.

A comparison evaluates to a boolean value. Thus, more complex conditions can be constructed with the help of boolean operators.

a = int(input('Choose a number from 1 to 10: '))

if (a >= 1) and (a <= 10):
    print('Well done!')
else:
    print('You still have to learn a lot...')    

The else part can be omitted, if nothing is to be done.

If more than two cases (True and False) have to be distinguished, use elif, which stands for ‘else if’:

a = int(input('Give me an integer: '))

if a < 0:
    print('It\'s a negative number.')
elif a == 0:
    print('It\'s zero.')
elif a < 10:
    print('It\'s a small positive number.')
else:
    print('It\'s a large positive number.')

Repeated Execution#

The second element of flow control, next to conditional execution, is repeated execution. Python provides two techniques: while loops and for loops.

For Loops#

A for loop repeats a code block a pre-specified number of times.

for k in range(1, 10):
    print(k * k)
1
4
9
16
25
36
49
64
81

Note that 100 is not printed. The loop always stops before the final number is reached.

Note

Whenever you have to define a range of integers in Python the upper bound has to be the last value you need plus 1. If you already tried some other programming language, this peculiarity of Python needs getting used to.

While Loops#

A while loop repeats a code block as long as a condition is met.

my_number = 10

users_number = int(input('Guess my number: '))

while users_number != my_number:
    if users_number < my_number:
        print('Too small!')
    else:
        print('Too large!')
    users_number = int(input('One more chance: '))

print('Correct!')

No Do-While Loops#

Many programming languages have a so called do-while loop. That’s like a while loop, but the condition is checked at the loop’s end. Thus, the loop’s code block is executed at least once. Python does not have a while loop.

Guido van Rossum, Python’s BDFL, rejected a Python enhancement proposal (PEP) which suggested to introduce a do-while loop with the following words:

Please reject the PEP. More variations along these lines won’t make the language more elegant or easier to learn. They’d just save a few hasty folks some typing while making others who have to read/maintain their code wonder what it means.

Controlling Loop Execution#

For and while loops provide the keywords break and continue. With break we can abort execution of the loop. With continue we can stop execution of the loop’s code block and immediately begin the next iteration.

Loops may have an else code block. The else block is executed if iteration terminates regularly. It is skipped, if iteration is stopped by break.

for k in range(1, 10):
    print(k)
    a = input('Do you want to see the next number (y/n)?')
    if a == 'n':
        break
else:
    print('Now you\'ve seen all my numbers.')
print('Good bye!')

Note

Whereas for and while loops are available in almost all programming languages, the else block is a special feature of Python.

Lists#

Next to the simple data types above there are more complex ones. Here we restrict our attention to lists. A list can hold a number of values. The length of a list is returned by the built-in function len. Square brackets [ and ] are used for defining a list and for accessing single elements of a list.

a = [2, -5, 4, 3, 2, -10, 3, 4]

print('List:', a)

print('Length of list:', len(a))

print('First element:', a[0])

print('Second element:', a[1])

print('Fifth element:', a[4])

print('Last element:', a[len(a) - 1])
List: [2, -5, 4, 3, 2, -10, 3, 4]
Length of list: 8
First element: 2
Second element: -5
Fifth element: 2
Last element: 4

List indices start with 0 in Python. Consequently, the last element of an n-element list has index n-1. The above code to access the last element is considered non-pythonic. Why this is the case and how to make it better will be discussed later on.

Lists may contain arbitrary types of data. Even lists of lists are allowed. This way we can construct two-dimensional data structures.

a = [[3, 4, 5], [-3, 7, 2], [4, 7, 5]]

print(a[0])

print(a[0][0], a[2][0])
[3, 4, 5]
3 4

Items of a list can be modified after creation of the list:

a = [3, 4, 5]
print(a)

a[1] = 1000
print(a)
[3, 4, 5]
[3, 1000, 5]

How to append elements to an existing list and many more list related topics will be discussed later on.

Note

A list may have length 0, that is, it may be empty. Empty lists occur frequently because often one wants to fill lists item by item, starting with an empty list. To get an empty list in Python write [].

Make a Building from Building Blocks#

With the above building blocks at hand we may write arbitrarily complex programs. There is nothing more we need. It’s like Lego blocks. Take lots of simple blocks, add some creativity, and think about how to reach your aim step by step.

All the other features of Python we’ll discuss soon only exist to simplify programming, save some time and make programs more readable. But they won’t add new possibilities.

Building everything from scratch is a long and winding road. So we’ll use other people’s code and combine it to new and larger projects. There’s a large library of ready-to-use code snippets, called the Python standard library. For specific tasks like data science and AI there are specialized libraries containg thousands of functions we may use without implementing them ourselves. Examples are Matplotlib, Pandas, Scikit-Learn and Tensorflow.