Introduction to Python

This tutorial introduces some important aspects of the Python programming language. For a more complete reference, have a look at the official Python tutorial.

Some Basic Date Types

Assign the integer number $3$ to the variable n. A variable name may contaoin letters (az, AB) and the underscore (_). All but the first character can also be positive integer number. Usually one uses lower case letters and underscores to seperate words.

In [ ]:
n = 3

Print the variable with print-command.

In [ ]:
print(n)

A string is given in single ticks (') or double ticks ("). If there is no other reason, we recommend single ticks.

In [ ]:
print('Welcome to the Python Tutorial')

Basic string formatting is possible:

In [ ]:
print('This is n: %d.' % n)
print('This is string1: %s and string2: %s.' % ('hi', 'hey'))
print('This is a floating point number: %06.3f.' % 3.14159265359)

Some basic math:

In [ ]:
n = 3
print('n + 1 =', n + 1)
print('n - 1 =', n - 1)
print('n * 2 =', n * 2)
print('n / 2 =', n / 2)
print('n ^ 2 =', n ** 2)

As you have seen, division always results in a floating point number (even if the number would be divisible without remainder). If the result should be an integer (e.g. for using it as an index), one may use the // operator:

In [ ]:
n = 4
print('Normal division:', n / 2)
print('Integer division:', n // 2)

For re-assigning a variable, one may use some semantic sugar.

In [ ]:
n = 3
n += 6
print(n)

n *= 2
print(n)

n /= 2
print(n)

n **= 0.5
print(n)

The basic compound data types in Python are lists and tuples. A list is enclosed in square brackets and a tuple is enclosed in round bracekts. Both are indexed with square brackets.

In [ ]:
lis = ['I', 'am', 'a', 'list']
tup = ('I', 'am', 'a', 'tuple')

print(lis)
print(tup)
print(lis[0], tup[1], 'generated from', tup[2], tup[3], 'and', lis[2], lis[3])

What's the difference between those two? Tuples are immutable and a bit more efficient. Lists are more flexible.

In [ ]:
lis = [1, 2, 3]
lis[0] = -1
lis.append(10)
lis = lis + ['a', '12', [13, 14]]
print(lis)
print(lis[-1])

The len function gives the length of a tuple or a list.

In [ ]:
print(len(tup))
print(len(lis))

One can index them with start, stop and step values. Negative indices run backwards. Leaving values out means start is the first item, end is the last item, and step is 1.

In [ ]:
lis = [11, 12, 13, 14, 15]
print('lis[0:2] =', lis[0:2])
print('lis[1:3] =', lis[1:3])
print('lis[0:4:2] =', lis[0:4:2])
print('lis[0::2] =', lis[0::2])
print('lis[::-1] =', lis[::-1])

The following examples shows how the elements of a list or tuple can be assigned to variables (called unpacking):

In [ ]:
lis = [1, 2]
[a, b] = lis
print(a, b)

tup = (3, 4)
[c, d] = tup
print(c, d)

Leaving out brackets, tuples are generated.

In [ ]:
a, b = 1, 2
print(a, b)

The range-function can be used to specify a tuple or list of integers (without actually generating these numbers):

In [ ]:
print(range(9))
print(range(1, 9, 2))

A range can then be converted into a tuple or list as follows:

In [ ]:
print(list(range(9)))
print(tuple(range(1, 9, 2)))
print(list(range(9, 1, -1)))

Boolean values in Python are True and False. Here are some examples for basic comparions:

In [ ]:
a = 1
b = 2
print(a < b)
print(a <= b)
print(a == b)
print(a != b)

The bool function converts an arbitrary value into a boolean value. Here, are some examples:

In [ ]:
print(bool('a'))
print(bool(''))
print(bool(1))
print(bool(0))
print(bool(0.0))
print(bool([]))
print(bool(()))

Basic Control Structures

For control structures such as if, for or while one has to use indentations (as part of the syntax). A typical Python convention is to use four spaces. For example, an if-statement is written as follows:

In [ ]:
n = 2
if n == 2:
    print('True')
else:
    print('False')

The next example shows how to use a for-looop. Note that an iterable may be specified by a range, a list, a tuple, or even other structures.

In [ ]:
for i in range(3):
    print(i, end=' ')
print()
    
for i in ['a', 2, 'c', 'def']:
    print(i, end=' ')
print()

for i in 'abcd':
    print(i, end=' ')
print()

A while-loop is written as follows:

In [ ]:
a = 0
while a < 3:
    print(a)
    a += 1

Functions

One defines functions with the def-keyword. As variable names, function names may contain letters (az, AB) and the underscore (_). All but the first character can also be positive integer number. Usually one uses lower case letters and underscores to seperate words.

In [ ]:
def add_one(n):
    print('Hello') 
    return n + 1

n is the single argument for the function named add_one. The return keyword is succeded by the return value.

In [ ]:
print(add_one(4))

We can give default values:

In [ ]:
def add(a, b=0, c=0):
    return a + b + c
In [ ]:
print(add(1))
print(add(1, 2))
print(add(1, b=2))
print(add(1, c=3, b=2))

There can also be multiple return values:

In [ ]:
def add_and_diff(a, b=0):
    return a + b, a - b

print(add_and_diff(1))
print(add_and_diff(1, 1))

NumPy

Python has several useful built-in packages. Further functionalities are provided by additional external packages. One such package is NumPy, which adds support for large, multi-dimensional arrays and matrices, along with a large collection of high-level mathematical functions to operate on these arrays. This tutorial touches only some important aspects – for a more complete reference, have a look at the numpy reference.

The NumPy package is imported as follows:

In [ ]:
import numpy as np

It is convenient to bind a package to a short name (for example np as above). This short name appears as prefix when calling a function from the package. This is illustrated by the following array-funtion provided by numpy:

In [ ]:
x = np.array([1, 2, 3, 3])
print(x)

Each array has a shape:

In [ ]:
print(x.shape)

Multi-dimensional arrays are created like follows:

In [ ]:
x = np.array([[1, 2, 3], [4, 5, 6]])
print(x)
print(x.shape)

There are a couple of functions for array creation:

In [ ]:
print('zeros', np.zeros(3))
print('ones', np.ones(3))
print('arange', np.arange(3))
print('empty', np.empty(3))
print('random.rand', np.random.rand(3))

print('eye\n%s' % np.eye(3))

Reshaping of an array is possible like follows:

In [ ]:
print('-- arange --')
x = np.arange(2 * 2 * 2 * 2)
print(x)
print(x.shape)

print('-- shape to (4, 4) --')
x = x.reshape((4, 4))
print(x)
print(x.shape)

print('-- shape to (2, 2, 2, 2) --')
x = x.reshape((2, 2, 2, 2))
print(x)
print(x.shape)

Normal operators, apply pointwise to such an array

In [ ]:
x = np.arange(5)
print('x + 1 =', x + 1)
print('x * 2 =', x * 2)
print('x > 2 =', x > 2)

Operators, performed on arrays of the same shape is always perfomed pointwise. Matrix multiplication is performed by using the function dot:

In [ ]:
a = np.arange(0, 9).reshape((3, 3))
b = np.arange(9, 18).reshape((3, 3))

print(a)
print(b)
print(a + b)
print(a * b)
print(np.dot(a, b))

Note, this is completly different from lists. E.g., addition may have a totally different result:

In [ ]:
a = np.arange(4)
b = np.arange(4)
a_plus_b = a + b
print(a_plus_b, type(a_plus_b))

a = list(a)
b = list(b)
a_plus_b = a + b
print(a_plus_b, type(a_plus_b))

Sometimes equality is a tricky thing in numerical computations. Floating numbers can be very close, but still different. Therefore, the isclose function is useful.

In [ ]:
print(np.isclose(x, x * 1.1))
print(np.isclose(x, x + 10 ** -8))

One may sum an array in total or across a given axis:

In [ ]:
x = np.arange(16).reshape((4, 4))
print(x)
print(x.sum())
print(x.sum(axis=0))
print(x.sum(axis=1))

We can index such an array like an Python list. But we have even more possibilities:

In [ ]:
print(x[x > 1])

index = np.array([[0, 1], [1, 2]])
print(x[index])

Specifying the data type for an array can be important in some situations.

In [ ]:
x = np.arange(-3, 3)
print(x)
x = np.sqrt(x)
print(x)

print()

x = np.arange(-3, 3, dtype='complex')
print(x)
x = np.sqrt(x)
print(x)

Matplotlib

Matplotlib is a plotting library for Python. The statement %matplotlib inline is for embedding matplotlib figures into Jupyter. In this section, there are few useful examples – for a more complete reference, have a look at the matplotlib documentation.

In [ ]:
%matplotlib inline
from matplotlib import pyplot as plt

x = np.arange(10)

plt.figure(figsize=(6, 6))
plt.plot(x, x ** 2, '-x', label='$f(x) = x^2$')
plt.plot(x, -(x ** 2), '-x', label='$f(x) = -(x^2)$')
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()
plt.legend()
In [ ]:
N = 10
x1 = np.arange(N * N).reshape((N, N))
x2 = x1 + N * (np.random.rand(N, N) - 0.5)

plt.figure(figsize=(12, 6))

plt.subplot(1, 2, 1)
plt.title('Without noise')
plt.imshow(x1, aspect='auto', origin='lower', cmap='viridis_r')
plt.colorbar()

plt.subplot(1, 2, 2)
plt.title('With noise')
plt.imshow(x2, aspect='auto', origin='lower', cmap='viridis_r')
plt.colorbar()

plt.tight_layout()
In [ ]: