Chapter 4 Introduction to Programming and Python

This chapters tries to cover enough basics of the Python programming language in order for you to get started with programming measurement software. Understanding of basic concepts will help you to look for more information from the Internet and understanding the terms used in programming books. If you want to read more about programming have a look at e.g. “Think Python” 1 , which a freely available programming book for beginners.

Box 4.1. Code examples

The code examples in this book are mostly minimal working examples, meaning that you can copy the code to Python terminal and it should run.

Overall programming is not difficult and anyone can learn it, but it does take some initial effort to learn how to think in terms of code and find out what methods are available etc. In the end the productivity gain that you get for research work (or any work that includes repetitive tasks using a computer) is really worth the effort.

4.1 Key Features of Python

We have chosen to use Python-programming language in this class. There exists several programming languages and many of them can also be used to program measurement systems.

Knowledge of one programming language means that it is much easier to learn new languages, because the basic ideas and constructs are usually very similar.

The main reason for choosing Python was that it is quite easy to learn and has good driver support for many instruments. Python is also taught in basic programming courses in many universities e.g. MIT and Aalto University.

Key Features:

  • Python is free and open source software.
  • Dynamically typed
  • Interpreted scripting language
  • Large standard library (batteries included)
  • Good scientific capabilities i.e. SciPy stack.
  • Significant whitespace : requires consistent indentation.
  • Runs on most operating systems: Windows, Mac OS X, Linux.

4.2 Getting Python and libraries

  • We use Anaconda Python distribution which includes several useful libraries. You can download it freely from: http://www.continuum.io/downloads
  • You can also get a free account to run Python in cloud from wakari.io
  • You should get Python 2.7, because it is the version that is supported by LabJack drivers. The book is written in a coding style that will mostly work in Python 2.7 and >= 3.3.4.
  • In addition to Anaconda you will need to get the pyageng -library https://pypi.python.org/pypi/pyageng/0.0.1 .

4.3 Ways to use Python

4.3.1 REPL

Python is an interpreted language which means you can run code directly using a REPL (read-eval-print-loop). This is also often called Python terminal. You can use the basic Python prompt, but many people like IPython better.

  • Python has a terminal that can be used to execute commands interactively.
  • IPython is an enhanced Python terminal.

4.3.2 Python scripts

  • Python programs are text files that consist of series of commands.
  • Generally we use *.py file extension for Python code.
  • Commands are executed in sequence one line at a time.
  • We’ll use Spyder IDE to edit and run Python scripts.

4.3.3 IPython Notebook

  • IPython notebooks are a mixture of documentation and code.
  • Notebooks can be edited interactively and published as a static webpage and converted to pdf.
  • Documentation can be written using markdown markup language 2
  • Notebooks are edited using a browser (Chrome, Firefox or Safari).

4.4 Variables and operators

Variables form the basics of any program. They are simply used to store data and by manipulating variables you can make complex computations.

Box 4.2. Variables
  • Variables are used to store values.
  • They can be of different type: int, float, string, bool.
  • Use command type to get the type of the variable.
  • Python uses dynamic typing so you don’t need to declare the type of variables yourself.
  • Variables are defined using the assignment operator = .

Defining variables is simple:

>>> a = 3 #Define variable a with value 3

4.4.1 Numeric variables

  • Numeric variables can be integers int or floating point numbers float .
  • Remember that integer division works differently from floating point division.
>>> x = 12  #Define integer variable x
>>> y = 8.0 #Define float y
>>> x/10 #Integer division
1
>>> x/10.0 #Floating point division
1.2

4.4.2 Basic Math

>>> import math
>>>
>>> 2 + 3
5
>>> 12.7 - 5
7.699999999999999
>>> 2**8 #Raise to power of 8
256
>>> math.sqrt(10)
3.1622776601683795
>>> 25 % 3 #Modulus
1

4.4.3 Strings

Text is represented using the string datatype. Python is very good at manipulating strings and can be used to format data collected from different sources with relative ease, even if some other program is used in further analysis.

Here is a demonstration of creating strings and using some string functions.

>>> s = "Agtek481" #Define a string
>>> s.upper() # Change case
'AGTEK481'
>>> s.replace("A", "B") #Replace A's with B's
'Bgtek481'
>>> s2 = " Measurement Technology"
>>> s + s2 # Joining two string together
'Agtek481 Measurement Technology'
>>> s[0:3] #Three first letters of s
'Agt'
>>> s2.split() # Split a string to a list of words.
['Measurement', 'Technology']

Escape sequences in strings

Python uses escape characters to represent special characters inside strings such as:

  • Linefeed “\n”
  • Carriage return “\r”
  • Tab “\t”
  • Backslash “\\”
  • You can use raw strings or two backslashes to include escape characters in text.

Some examples:

>>> print("First line\nSecond line") # Test with linefeed
First line
Second line
>>> print("Column1\tColumn2") #Tab
Column1 Column2
>>> print(r"Column1\tColumn2") #Raw string
Column1\tColumn2

4.4.4 Booleans

The boolean datatype bool has two possible values True and False . It can be used to compare different objects together. You’ll learn more about comparison in the section about sec-condconditionals.

>>> a = 5
>>> a > 3
True
>>> a > 10
False

4.4.5 Naming variables

You should follow a naming convention to make your code more readable. Programming languages often have recommended conventions or they can be defined separately for each team or project.

Here are some conventions that are usual to Python code and is also followed in this book:

  • Choose readable names, favor readability over brevity.
  • Use lowercase letters for variable and function names.
  • Use underscore to separate words in variable names e.g. outside_temperature
  • Use CamelCase for class names.

4.4.6 Variable scope

Variables declared inside the function body are local to that function. Each function declares a new namespace called scope with each execution. This means that the variables you create in function body are lost after executing the function. This is generally a good thing and keeps your workspace cleaner.

If you need to you can make variables global so that they are accessible from any namespace (main program and all functions), but this is generally not recommended. It can however sometimes be useful for debugging purposes.

If you need to see what values local variables inside a function have you can use print statements inside the function.

4.5 Operators

Operators are special symbols that can be used to represent computations such as addition and subtraction. Operators in programming languages are similar to those in mathematics, but they are not the same. Also there are differences between languages. You can see some Python operators in the following table:

Operator Action
= Assignment. Left side is assigned the value of the right side.
+ Addition for numbers. Concatenation for strings.
- Subtraction
* Multiplication
/ Division
% Modulus
** Power
+= Incremental addition. e.g. x+=5; is the same as x = x + 5;
-= Incremental decrement
*= Multiple by
/= Divide by
Table 4.1: Some Python operators

4.6 Keywords

Keywords are reserved words that have a special meaning, you can’t use them for user defined types.

Python keywords:

and del for is raise assert elif from lambda return break else global not try
class except if or while continue exec import pass yield def finally in print

4.7 Collections

4.7.1 Lists

Instead of keeping data in a single variable we often need to keep multiple elements of the same type together. For instance we want to collect measurement data together for plotting and calculating statistics etc. Or we need to keep a list of different options under the collection. Python has a list datatype for the very purpose.

  • A list is an ordered collection of items.
  • Lists can hold items of any data type including other lists.
  • Elements can be accessed by their index
  • Lists are mutable , their elements can be changed after they have been created.
>>> l = [3.0, 4.0, 12, 5, 2.3, 8] # A list of numbers
>>> sum(l) #Sum of all elements
34.3
>>> len(l) #Length of the list
6
>>> l[0] #First element of a list
3.0
>>> l[2:5] # Elements from indices 2-4
[12, 5, 2.3]

Creating List of numbers:

  • You can create a list of numbers using the range command
  • Note that the endpoint is not included in the list.
>>> range(10) # Numbers from 0 to 9
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 20, 3) #Every third number from 1 to 19
[1, 4, 7, 10, 13, 16, 19]

The fact that lists are mutable can lead to some unexpected behavior. For example when you pass a list to function it receives the original list and can modify it. If you want to make sure that the original list is not modified you need to make a copy of the list.

Have a look at the example below where list animals is assigned to list animals2 . Contrary to what we might expect animals2 becomes an alias 3 for animals so that modifying animals2 also changes the original list.

>>> animals = ["cow", "pig", "sheep"]
>>> animals2 = animals #An alias of the list
>>> animals2[0] = "chicken"
>>> animals #Modifying l2 also modified l
['chicken', 'pig', 'sheep']

We can avoid this behavior by making a copy of the original list:

>>> animals2 = animals[:] #Make a copy instead
>>> animals2[0] = "turkey"
>>> animals
['chicken', 'pig', 'sheep']
>>> animals2 #Now only animals2 was modified
['turkey', 'pig', 'sheep']

4.7.2 Tuples

  • Tuples are similar to lists, but they are immutable .
  • They are useful if you want a list of items that can’t be modified.
  • Many Python functions return tuples.
  • Items can be accessed using indexing or unpacking.
>>> t = (1, 3, 8) #Create a tuple
>>> t[1] #Acces by index similar to lists
3
>>> t2 = ("one", "two")
>>> a,b = t2 #Unpack the values to variables a and b
>>> a
'one'
>>> b
'two'

4.7.3 Dictionaries

  • Dictionaries are unordered collections of key,value pairs.
  • They are indexed by keys.
  • Keys can be any immutable type; strings and numbers can always be keys
>>> cow = {"id" : 230, "yield" : 35.2, "visits" : 2}
>>> cow["id"]
230
>>> cow["visits"] = 3 #Modify a key
>>> cow["name"] = "Tuopilla" #Add a key
>>> cow
{'visits': 3, 'id': 230, 'yield': 35.2, 'name': 'Tuopilla'}
>>> list(cow.keys())
['visits', 'id', 'yield', 'name']
>>> list(cow.values())
[3, 230, 35.2, 'Tuopilla']

4.8 Iteration and conditionals

Iteration is a key element in programming. It allows us to perform same tasks repeatedly. We can for instance:

  • Collect data from sensors repeatedly with a fixed time interval.
  • Process a number of files with same analysis code.
  • Perform iterative search in numeric algorithms until a desired answer is found.

4.8.1 For loop

A for loop iterates over a specified number of elements. The body of the loop is separated using whitespace : it is indented. Here we create a list of numbers from 0 to 4 (using the range command), iterate trough each element and print the answer to screen. This kind of loop can be used e.g. to take a certain number of samples from a datalogger.

for i in range(5):
    print(i)
0
1
2
3
4

4.8.2 Iterating trough a sequence

For loop is commonly used to iterate over collections. Here we iterate over elements of list l and print the square root of each elements.

n = len(l)
for i in range(n):
    print("Square root of " + str(l[i]) + " is "
             +  str(math.sqrt(l[i])))
Square root of 3.0 is 1.73205080757
Square root of 4.0 is 2.0
Square root of 12 is 3.46410161514
Square root of 5 is 2.2360679775
Square root of 2.3 is 1.51657508881
Square root of 8 is 2.82842712475

The loops before are iterating over a list, the elements just happened to be numbers. You can also iterate over a list of other types e.g strings.

>>> animals = ["cow", "pig", "sheep"]
>>>
>>> for animal in animals:
...     print(animal)
...
cow
pig
sheep

You can also iterate over the indexes and values at the same time using the enumerate command.

>>> for index,value in enumerate(l):
...     print(index, value)
...
(0, 3.0)
(1, 4.0)
(2, 12)
(3, 5)
(4, 2.3)
(5, 8)

4.8.3 Iterating over a dictionary

You can iterate over the keys of a dictionary. Remember that keys are unordered so the order of keys is arbitrary.

>>> for key in cow.keys():
...     print(key)
...
visits
id
yield
name

Or keys and values at the same time:

>>> for key, value in cow.items():
...     print(key, value)
...
('visits', 3)
('id', 230)
('yield', 35.2)
('name', 'Tuopilla')

4.9 Conditional statements

Conditional statements are used to control whether a certain block of code should execute. The body of an if statement is evaluated the condition is True . You can also use an optional elif and/or else statements. Conditions are formed using comparison operators shown in the following table.

Suppose we measure temperature T and want to control a heater based on it using three power levels.

if T < 10:
    power = 100
elif T < 20:
    power = 50
else:
    power = 0

4.10 Combining conditions

You can combine conditional statements using and and or operators. Conditional statements can also be grouped using parentheses.

Turn a heater on if Temperature (T) is too low or relative humidity (RH) is too high.

if T < 15 or RH > 80: #Suppose T and RH come from a measurement
    heater = True
Operator Meaning
== equals
!= not equals
< less than
> greater than
<= Less than or equal to
>= Greater than or equal to
and Logical AND
or Logical OR
not Logigal negation
in Test if an element is a member of a sequence
Table 4.2: Operators for conditional statements.

4.11 While loop

A while loop executes the loop body as long an expression is True. It is used when we don’t know how many times the loop should run.

In simple measurement program we often use an infinite loop which will run until a user closes the program. You can also accidentally write a while loop that will never terminate if you get the terminating condition wrong.

A loop that runs while \( a < 5 \)

a = 0
while a < 5:
    print(a)
    a += 1
0
1
2
3
4

4.11.1 Example: Finding the square root

  • Heron’s method is the first explicit description on how to compute a square root.
  • Here’s how its used to find \( \sqrt{x} \)
    1. Start with a guess, g.
    2. If \( g \cdot g \) is close enough then stop.
    3. Otherwise create a new guess g using \( \frac{g+\frac{x}{g}}{2} \)
x = 10
g = 2.0 #Initial guess
error = 1 #Init error
while abs(error) > 0.0001:
    g = (g + (x/g))/2
    error = x - g*g
    print("guess", g, "error", error)

print("Square root of", x, "is", g)
guess 3.5 error -2.25
guess 3.17857142857 error -0.103316326531
guess 3.16231942215 error -0.000264127712693
guess 3.16227766044 error -1.74403957942e-09
Square root of 10 is 3.16227766044

4.12 Functions and modules

Functions can be used group related functionality together. They enable reuse of code and make programs more readable.

We have already used several built in functions, but now it is time to learn how you can write your own functions.

4.13 Defining functions

Function definition in Python is very simple. They are defined using the def keyword and you can even define functions from the terminal. The return value of the functions is defined with return statement.

Let’s have a look at a simple example of defining a function:

def adder(x, y):
    """Computes the sum of two numbers"""
    return x + y

And here is how its used:

>>> adder(3, 2)
5
>>> adder(2.5, 1.8)
4.3

The sequence of names in parentheses after a function definition are called the formal parameters of the function. When the function is called the arguments of the function are bound to the formal parameters.

For the function adder defined above:

  • x and y are the formal parameters
  • with the call adder(3, 2) , 3 and 2 are the arguments.

Functions a documented using docstring s i.e. a string following immediately after function declaration. You can see an example of a docstring above.It is a good idea to take the time to write a descriptive docstring for your functions.

4.14 Modules

  • A Python module is used to group related code for easy reuse.
  • A package can contain several modules with separate namespace.

Python has several built in packages and Anaconda comes with several third party modules as well. You can make your own module by placing a *.py file in your working directory and import data and methods from it.

4.14.1 Importing code from modules

The import is used to get commands from modules. There are 3 ways to use import:

  • import module
  • from module import object
  • from module import *

Its recommended not to use the third one in scripts. Here is a small example about how to use three methods using math module:

>>> import math
>>> math.pi #Use fully qualified name
3.141592653589793
>>> from math import pi #Only import pi to main namespace
>>> pi
3.141592653589793
>>> from math import * #Import all objects from math to namespace
>>> pi
3.141592653589793

4.15 Files

Python has a built in file type. You can open a file for reading, writing or both with open command. When writing you can choose to overwrite the existing file (“w” option) or append to file (“a” option). We’ll only handle working with text files here.

Open a file for writing and add text to it:

4.15.1 Writing files

datafile = open("sample1.txt", "w") #"w" opens for writing
datafile.write("Starting measurement\n")
datafile.close()

Append data to the same file:

datafile = open("sample1.txt", "a") #"a" stands for appending
for i in range(3):
    datafile.write("Line " + str(i) + "\n")
datafile.close()

4.15.2 Reading files

  • It is easy to read in the whole file in Python using read , readline or readlines methods.

Read a file to a string using read method:

>>> datafile = open("sample1.txt", "r")
>>> text = datafile.read()
>>> datafile.close()
>>> text
'Starting measurement\nLine 0\nLine 1\nLine 2\n'

Read to a list of lines:

>>> datafile = open("sample1.txt", "r")
>>> textlines = datafile.readlines()
>>> datafile.close()
>>> textlines
['Starting measurement\n', 'Line 0\n', 'Line 1\n', 'Line 2\n']

4.16 Date and time

>>> from datetime import datetime
>>> datetime.now() #Get current time
datetime.datetime(2016, 2, 14, 20, 28, 56, 692234)
>>> #Get ISO formatted time
>>> datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
'2016-02-14 20:28:56'
>>> vappu = datetime(2014, 5, 1) #Create a datetime object
>>> kesto = vappu - datetime.now()
>>> print(str(kesto.days) + " days to vappu")
-655 days to vappu

4.16.1 File formatting for measurements

A common problem in writing measurement software is not thinking about analysis stage when you collect the data. Knowing what software you’ll be using is advantageous, because you can then save your data in a format that is easy to open with the program of your choosing.

Here are some general rules to bear in mind:

  • Use clear separators between fields, such as comma or space.
  • Use automatic file naming if possible.
  • Make sure that the format you use is easy to open in later analysis.
    • Make sure you can open the files with correct formatting before collecting a lot of data.
    • Make sure you can handle dates in correct format.
  • Include time for each sample or at least the start time and sampling rate in file name or header.
  • Its best to use plain text format if possible.
  • Always preserve the raw text files when doing analysis: always keep a back up of the original file .