3.1.1. Python Quick Reference

Python is a high-level open-source language. This page is written with the use of Python in mind, as opposed to computer science definitions. iPython is used here because:

3.1.1.1. Modules

3.1.1.1.1. Definition

  • Modules provide useful functions, such as array operations, plotting and much more.

  • We can import the module to allow access to the functions

In [1]: # comments in python are denoted by the hash tag

In [2]: import numpy as np # for matrix operations

In [3]: import matplotlib.pyplot as plt # for 2D plotting
  • We have defined the following aliases:

    Module

    Alias

    Purpose

    numpy

    np

    Matrix Operations

    matplotlib.pyplot

    plt

    2D Plotting

3.1.1.1.2. Use

  • This allows reference to the modules via the alias, e.g.

In [4]: myarray = np.linspace(0,5,10)

In [5]: myarray
Out[5]: 
array([0.        , 0.55555556, 1.11111111, 1.66666667, 2.22222222,
       2.77777778, 3.33333333, 3.88888889, 4.44444444, 5.        ])
  • If you don’t preface the linspace function with np python will throw an error:

  • To learn the new functions available to you, visit: Numpy Reference

  • Or for Matlab users: Numpy for Matlab Users

3.1.1.2. Variables

3.1.1.2.1. Definition

Python doesn’t require explicitly declared variable types like C and Fortran.

In [6]: a = 5 # a is an integer 5

In [7]: b = 'five' # b is a string of the word 'five'

In [8]: c = 5.0 # c is a floating point 5

3.1.1.2.2. Use

Use type to determine the type of variable:

In [9]: type(a)
Out[9]: int

In [10]: type(b)
Out[10]: str

In [11]: type(c)
Out[11]: float

Division using integers is in two ways:

  • Integer / Integer = Integer

In [12]: 14 / 3
Out[12]: 4.666666666666667
  • Integer / Float = Float

In [13]: 14 / 3.0
Out[13]: 4.666666666666667

3.1.1.3. Whitespace in Python

Python uses indents and whitespaces to group statements together. To write a loop in C you might use:

for (i = 0, i < 5, i++){
    printf("Hi! \n");
}

Or in Fortran:

do i = 1, 4
    print *, "Hi!"
    print *, " "
enddo

Python doesn’t use curly braces like C or the enddo like Fortran. The Python equivalent is:

for i in range(5):
    print "Hi! \n"

If you have nested for-loops, there is a further indent for the inner loop:

In [14]: for i in range(3):
   ....:     for j in range(3):
   ....:        print i, j
   ....:     print "This statement is within the i-loop but not the j-loop"
   ....: 
  File "<ipython-input-14-32b2a2b7a13c>", line 3
    print i, j
          ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(i, j)?

3.1.1.4. Arrays

3.1.1.4.1. Creation of Arrays

  • NumPy arrays are created from lists

In [15]: myvals = np.array([1,2,3,4,5])

In [16]: myvals
Out[16]: array([1, 2, 3, 4, 5])

In [17]: type(myvals)
Out[17]: numpy.ndarray
  • Or using linspace:

In [18]: myvals2 = np.linspace(1,5,5)

In [19]: myvals2
Out[19]: array([1., 2., 3., 4., 5.])

In [20]: type(myvals2)
Out[20]: numpy.ndarray

3.1.1.4.2. Index

  • Python uses a zero-based index:

    • The first element is 0

    • The last element is n-1 where n is the number of values in the array

In [21]: myvals[0], myvals[4]
Out[21]: (1, 5)

3.1.1.4.3. Slicing Arrays

  • The slice is inclusive on the front end and exclusive on the back, so the following command gives us the values of myvals[0], myvals[1] and myvals[2]

  • myvals[3] is excluded

In [22]: myvals[0:3]
Out[22]: array([1, 2, 3])
  • For a[start:end] THE INDEX DENOTES THE POSITION OF THE SLICE - NOT THE ELEMENT:

#                  +------+------+---   ---+------+------+
#                  |  11  |  22  |   33    |  44  |  55  |
#                  +------+------+---   ---+------+------+
# Long version:    0      1      2      nx-2   nx-1     nx
# Short version:                          -2     -1
In [23]: hello = np.array([11, 22, 33, 44, 55])
  • So now test it:

In [24]: hello[0:-1]
Out[24]: array([11, 22, 33, 44])

In [25]: hello[1:-2]
Out[25]: array([22, 33])

In [26]: hello[:-1]
Out[26]: array([11, 22, 33, 44])

3.1.1.4.4. Slicing Arrays (Short Notation)

In [27]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

3.1.1.4.4.1. Indexing

Index notation occurs when only one character appears in the square brackets

  • The first value:

In [28]: alpha[0]
Out[28]: 'a'
  • The last value:

In [29]: alpha[-1]
Out[29]: 'f'
  • All the values

In [30]: alpha[:]
Out[30]: ['a', 'b', 'c', 'd', 'e', 'f']

3.1.1.4.4.2. Slicing

The slice notation occurs with a number included to the left or right of the colon

  • From the second value onwards:

In [31]: alpha[1:]
Out[31]: ['b', 'c', 'd', 'e', 'f']
  • From the third value onwards:

In [32]: alpha[2:]
Out[32]: ['c', 'd', 'e', 'f']
  • All the values except the last value:

In [33]: alpha[0:-1]
Out[33]: ['a', 'b', 'c', 'd', 'e']

In [34]: alpha[:-1]
Out[34]: ['a', 'b', 'c', 'd', 'e']
  • All the values except the last two values:

In [35]: alpha[0:-2]
Out[35]: ['a', 'b', 'c', 'd']

In [36]: alpha[:-2]
Out[36]: ['a', 'b', 'c', 'd']
  • From the second value to the second to last value:

In [37]: alpha[1:-1]
Out[37]: ['b', 'c', 'd', 'e']

3.1.1.4.5. Assigning Array Variables

One of the strange little quirks/features in Python that often confuses people comes up when assigning and comparing arrays of values.

  • Create 1D array called a:

In [38]: a = np.linspace(1,5,5)

In [39]: a
Out[39]: array([1., 2., 3., 4., 5.])
  • Make a copy of a and call it b (this is actually assignment by reference)

In [40]: b = a

In [41]: b
Out[41]: array([1., 2., 3., 4., 5.])
  • Now try changing the values in a:

In [42]: a[2] = 17

In [43]: a
Out[43]: array([ 1.,  2., 17.,  4.,  5.])
  • But this also changed b!

In [44]: b
Out[44]: array([ 1.,  2., 17.,  4.,  5.])

Explanation: Python created a pointer called b that tells us to route it to a. This is called assignment by reference.

3.1.1.4.6. Copying Arrays

If you want to make a true copy of the array you have to tell Python to copy every element of a into a new array:

  • Create an empty array c the same length as a:

In [45]: c = np.empty_like(a)

In [46]: len(c) # tells us how long c is
Out[46]: 5
  • Copy the values from a to c:

In [47]: c[:] = a[:]

In [48]: c
Out[48]: array([ 1.,  2., 17.,  4.,  5.])
  • Now change a value in a, which doesn’t change c:

In [49]: a[0] = 200

In [50]: a
Out[50]: array([200.,   2.,  17.,   4.,   5.])

In [51]: c
Out[51]: array([ 1.,  2., 17.,  4.,  5.])

3.1.1.4.7. Array Operations

3.1.1.4.7.1. Operators

Addition on a list is concatenation:

In [52]: a = [1,2,3]

In [53]: a + a
Out[53]: [1, 2, 3, 1, 2, 3]

Arithmetic operations on an array are element-wise:

In [54]: b = np.array([1,2,3])

In [55]: b + b # element-wise addition
Out[55]: array([2, 4, 6])

In [56]: b - b # element-wise subtract
Out[56]: array([0, 0, 0])

In [57]: b / b # element-wise divide
Out[57]: array([1., 1., 1.])

In [58]: b * b # element-wise muliply
Out[58]: array([1, 4, 9])

In [59]: b ** 2 # element-wise power
Out[59]: array([1, 4, 9])

3.1.1.4.7.2. Functions

Functions on arrays are element-wise:

In [60]: np.sin(b) # element-wise sin - use np.sin for this operation not math.sin
Out[60]: array([0.84147098, 0.90929743, 0.14112001])

3.1.1.4.7.3. Dot Product

\[\begin{split}\begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} \cdot \begin{bmatrix} 1 & 2 \\ 3 & 4 \\ 5 & 6 \end{bmatrix} = \begin{bmatrix} 22 & 28 \\ 49 & 64 \end{bmatrix}\end{split}\]

Dot product on an array:

In [61]: horz = np.array([[1,2,3],[4,5,6]])

In [62]: vert = np.array([[1,2],[3,4],[5,6]])

In [63]: np.dot(horz,vert)
Out[63]: 
array([[22, 28],
       [49, 64]])

3.1.1.4.7.4. Array Creation

Lists can be created using range:

In [64]: range(5)
Out[64]: range(0, 5)

Arrays can be created using arange or linspace:

In [65]: np.arange(5)
Out[65]: array([0, 1, 2, 3, 4])

In [66]: np.linspace(0,4,5)
Out[66]: array([0., 1., 2., 3., 4.])

3.1.1.4.7.5. List Comprehension

  • Imagine a list of three numbers:

In [67]: c = [1,2,3]
  • The list comprehension:

In [68]: cc = [x+y for x,y in zip(c,c)]

In [69]: cc
Out[69]: [2, 4, 6]
  • Where zip returns a list of tuples, i.e.

In [70]: zip(c,c)
Out[70]: <zip at 0x7fb3b14be588>
  • The list comprehension is equivalent to:

In [71]: dd = []

In [72]: for x,y in zip(c,c):
   ....:    dd.append(x+y)
   ....: 

In [73]: dd
Out[73]: [2, 4, 6]
  • Or:

In [74]: e = np.array(c)

In [75]: ee = e + e

In [76]: ee
Out[76]: array([2, 4, 6])

3.1.1.4.8. Which is Faster: Lists or Arrays?

Create a list and time a list comprehension:

In [77]: f = range(10000)

In [78]: timeit ff = [x + y for x,y in zip(f,f)]
549 us +- 7.26 us per loop (mean +- std. dev. of 7 runs, 1000 loops each)

Create a NumPy array and time the addition:

In [79]: g = np.array(f)

In [80]: timeit gg = g + g
2.78 us +- 349 ns per loop (mean +- std. dev. of 7 runs, 100000 loops each)

In [81]: timeit hh = np.add(g,g)
2.6 us +- 10.1 ns per loop (mean +- std. dev. of 7 runs, 100000 loops each)
  • NumPy is over 100 times faster than Lists.

  • Not much between np.add and +.

  • Readability of + probably outweighs slight speed penalty.