Introduction#
\(\newcommand{\re}{\mathbb{R}}\) Python comes in two versions, 2 and 3. Version 2 is still available on some old computers but it is deprecated and should not be used. Hence we will use version 3 throughout these lectures. To see if Python is already installed
which python
You can check the version like this on the terminal
$ python --version
On some systems, you may have to use python3
to get version 3 python.
Usually Python is available on Linux/Unix computers, though it may not provide all the required libraries. You can install them using your system package manager (apt on Debian/Ubuntu) or by installing a full Python distribution like Miniforge. It is highly recommended to use Conda to install Python, rather than using your system package manager. If you use Conda, then make sure to set your PATH
variable so that it finds Anaconda python rather than your system python.
export PATH=/path/to/miniforge/bin:$PATH
Then test that the correct python is in your PATH
$ which python
Python is organized into modules and some of the useful Python modules we will use in this tutorial are
numpy: provides arrays, linear algebra, random numbers, etc.
scipy: integration, optimization, linear algebra
matplotlib: for making graphs
sympy: symbolic math
There are several ways to use Python.
python: type this in terminal, very basic, does not have interactivity or help
$ python
Python 3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:25:13) [Clang 14.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
ipython: better python terminal
Python 3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:25:13) [Clang 14.0.6 ]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.7.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
pylab: imports some modules like numpy; define an alias
alias pylab="ipython --pylab --matplotlib --nosep --pprint"
jupyter notebook: This is what you are reading now. On some computers you can start a notebook using
$ ipython-notebook (conda install notebook)
$ jupyter-lab (conda install jupyterlab)
I prefer using jupyterlab since it seems more modern.
Basic math#
The basic number types we commonly use are integers, reals and complex numbers. In Python, we can directly use variables without declaring their type. This is in contrast to most other programming languages like Fortran/C/C++ where the type of variable has to be declared before using it.
x = 1
y = 2
z = x + y
print(z)
3
The type of the variable is automatically determined by what we assign to it.
print(type(x),type(y),type(z))
<class 'int'> <class 'int'> <class 'int'>
x = 1.0
y = 2.0
z = x + y
print(z)
print(type(z))
3.0
<class 'float'>
The float type corresponds to double precision in C/C++ and has about 16 decimal places of accuracy. It is good programming practice to assign numerical values based on their intended type. If you want x
to be a float then assign its value as x = 1.0
and not as x = 1
.
Python will automatically determine the type when you have mixed types in some expression.
a = 1
b = 2.345
c = a + b
print(c)
print(type(a),type(b),type(c))
3.345
<class 'int'> <class 'float'> <class 'float'>
Implicit typing reduces code clutter, but there is potential for making mistakes, so be careful to set correct values to reflect the intended type.
Variable names are case sensitive; below a
and A
are different variables.
a = 1
A = 2
print('a = ',a,', A = ',A)
a = 1 , A = 2
Division is performed using backslash symbol
x = 1.0
y = 3.0
z = x/y
print(z)
0.3333333333333333
Division of integers still returns a float (This behaviour was different in Version 2 and earlier).
print(1/2)
0.5
Integer division can be performed with double backslash operator
print('1/2, 1//2 =', 1/2, 1//2)
print('1/3, 1//3 =', 1/3, 1//3)
print('2/3, 2//3 =', 2/3, 2//3)
print('3/2, 3//2 =', 3/2, 3//2)
print('5/3, 5//3 =', 5/3, 5//3)
1/2, 1//2 = 0.5 0
1/3, 1//3 = 0.3333333333333333 0
2/3, 2//3 = 0.6666666666666666 0
3/2, 3//2 = 1.5 1
5/3, 5//3 = 1.6666666666666667 1
The result is rounded down to the integer value.
Raising to some power
is done like this
a, b = 3, 2
c = a**b
print(c)
9
If the power \(n\) in
is an integer, declare \(n\) as integer 2 which will be faster than if you declare it as 2.0.
x, n = 1.234, 2
y = x**n
print(x,n,y)
1.234 2 1.522756
Formatted print#
We can use C-style formatting
i = 10
x = 1.23456789
print('i, x = %5d %12.6f %14.6e' % (i,x,x))
i, x = 10 1.234568 1.234568e+00
Since we used 6 decimal places, the floating point numbers are rounded. The exponential form is preferred if we have very small or very large numbers.
x = 0.0000000123456
print('%16.6f %16.6e' % (x,x))
0.000000 1.234560e-08
Math functions#
The basic Python language does not have mathematical functions like sin, cos, etc. These are implemented in additional modules. The math
module provides many of these standard functions. We have to first import the module like this
import math
Now we can use the functions available in this module.
x = 10.0
z = math.sin(x)
print(z)
-0.5440211108893698
Value of \(\pi\)
print(math.pi)
3.141592653589793
On import#
We can also import everything into the current workspace and then we can use it without prepending math
>> from math import *
>> x = sin(1.5*pi)
but this is not recommended usage since there may exist functions with same name in different modules. We can also import only what we need, e.g.,
from math import sin,cos,pi
Strings#
Strings can be created by enclosing characters between single quote or double quotes.
a, b, c, d = 'Hello', ',', ' ', 'World!'
print(a+b+c+d)
Hello, World!
Addition operator on strings concatenates them.
If we want to create a string of the form sol_100.txt
base = 'sol_'
it = 100
ext = '.txt'
filename = base + str(it) + ext
print(filename)
sol_100.txt
Lists#
Lists allow us to store a collection of objects. Here is a list of integers
a = [1, 2, 3, 4, 5]
print(a)
[1, 2, 3, 4, 5]
But lists can be made up of different types of elements.
b = [1, 2.0, 3.0, 4, 'x']
print(b)
[1, 2.0, 3.0, 4, 'x']
Lists look like vectors but they do not obey rules of algebra.
x = [1, 2, 3]
y = [5, 6, 1]
print(x + y)
[1, 2, 3, 5, 6, 1]
Note that x
and y
have been concatenated. So a list behaves more like a set, but they are not sets since elements in a list can be repeated. To get the behaviour of vector addition, use Numpy arrays which we discuss later.
We can access an element of a list using its index
print('x =',x)
print('x[0] =',x[0])
print('x[1] =',x[1])
print('x[2] =',x[2])
x = [1, 2, 3]
x[0] = 1
x[1] = 2
x[2] = 3
Indices in Python start from 0.
You can get the length of a list using len
.
print(x)
print(len(x))
[1, 2, 3]
3
We can modify the elements of a list
x[1] = 0
print(x)
[1, 0, 3]
We can incrementally build a list
a = [] # empty list
a.append(1)
a.append(2)
a.append(3)
print(a)
[1, 2, 3]
Tuples#
Tuples are similar to lists but they cannot be modified, they are immutable.
x = (1,2,3)
print(x)
print(x[0])
print(x[1])
print(x[2])
(1, 2, 3)
1
2
3
Try to modify some element of a tuple, for example
x[1] = 0
NOTE: Lists and tuples can contain elements of different types
a = [1,2,'a']
b = (1,2,'a')
print("a = ", a)
print("b = ", b)
a = [1, 2, 'a']
b = (1, 2, 'a')
Sets#
A set is a collection of some objects which can be of any and different types.
a = {1, 2, 3, 'a', 'b', 'c'}
print(a)
{'b', 1, 2, 3, 'a', 'c'}
Elements of a set must be unique.
b = {1, 2, 3, 3}
print(b)
{1, 2, 3}
Minus performs set minus.
a = {1,2,3,4}
b = {1,2,3}
print(a-b)
print(b-a)
{4}
set()
Union of sets
c = {1,2,3,4}
d = {3,4,5,6}
print(c.union(d))
print(c|d)
{1, 2, 3, 4, 5, 6}
{1, 2, 3, 4, 5, 6}
For loops#
for i in range(5):
print(i)
0
1
2
3
4
range(n)
produces the integers: \(0,1,2,\ldots,n-1\). Note: \(n\) is not included.
print(range(5))
print(type(range(5)))
range(0, 5)
<class 'range'>
Specify both start and end
for i in range(5,10):
print(i)
5
6
7
8
9
range(m,n)
produces the integers: \(m,m+1,\ldots,n-1\) provided \(m < n\).
for i in range(0,10,2):
print(i)
0
2
4
6
8
range(m,n,s)
produces the integers: \(m,m+s,m+2s,\ldots\) until \(n\), but excluding \(n\).
We can have a negative step size.
for i in range(10,0,-2):
print(i)
10
8
6
4
2
Again, the last element, here 0, is not included.
In built manual/help#
To see the inbuilt manual in terminal
>>> range?
This works for all functions, etc.
>>> import math
>>> math.sin?
In a notebook, type this in a code cell
range?
get the help documentation.
Example: Sum a list of integers#
Given a vector \(a \in \re^n\), compute the sum of its element
We will need some mechanism to iterate over the elements to compute the sum, and we can use a for
loop.
a = [1,2,3,4,5,6,7,8,9,10]
s = 0
for x in a:
s += x
print('Sum = ',s)
Sum = 55
Note that s += x
is shorthand for s = s + x
. Since we accumulate the sum into s
, we have to first initialize it to zero.
Another way is to use indices
s = 0
for i in range(len(a)):
s += a[i]
print('Sum = ',s)
Sum = 55
while loop#
A for
loop is useful when we know a-priori how many steps we have to do. When we dont know in advance how many steps are needed, a while
loop may be more useful.
Example: Generate independent uniform random numbers \(x_j\) such that
We dont know the value of n
a-priori.
import random
s, i = 0.0, 0
while s < 10.0:
s += random.random()
i += 1
print("%5d %20.10f" % (i,s))
1 0.5940166748
2 1.2818454959
3 1.5974936223
4 2.1392944746
5 2.9149129007
6 3.0732040697
7 3.0880344636
8 3.3358875641
9 3.3415009088
10 3.3792213245
11 4.1367973168
12 4.8236956917
13 5.2520791720
14 6.1970159750
15 6.7005327811
16 6.7540986939
17 6.9850782977
18 7.3449310783
19 7.7279754536
20 8.4521317429
21 8.4684857437
22 8.6397382858
23 9.1490734198
24 9.4050665941
25 9.6616819777
26 10.1777617676
Note how we controlled the printing of numbers: d
is for integers, f
is for floating point numbers. You can also use e
for scientific notation.
enumerate#
Another way to iterate over an array-type object where we get both index and element value is using enumerate.
values = [1.2, 2.3, 3.4, 4.5, 5.6]
for i,val in enumerate(values):
print(i," ",val)
0 1.2
1 2.3
2 3.4
3 4.5
4 5.6
Swapping#
a, b = 1, 2
print('Before: a = ',a,', b = ',b)
tmp = a
a = b
b = tmp
print('After : a = ',a,', b = ',b)
Before: a = 1 , b = 2
After : a = 2 , b = 1
In Python, swapping can be done as
a, b = 1, 2
print('Before: a = ',a,', b = ',b)
a, b = b, a
print('After : a = ',a,', b = ',b)
Before: a = 1 , b = 2
After : a = 2 , b = 1