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.
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.
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:
pyageng
-library
https://pypi.python.org/pypi/pyageng/0.0.1
.
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.
Variables form the basics of any program. They are simply used to store data and by manipulating variables you can make complex computations.
type
to get the type of the variable.
assignment
operator
=
.
Defining variables is simple:
>>> a = 3 #Define variable a with value 3
int
or floating point numbers
float
.
>>> 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
>>> 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
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']
Python uses escape characters to represent special characters inside strings such as:
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
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
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:
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.
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 |
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
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.
>>> 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:
range
command
>>> 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']
>>> 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'
>>> 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']
Iteration is a key element in programming. It allows us to perform same tasks repeatedly. We can for instance:
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
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)
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')
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
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 |
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
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
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.
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
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.
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.
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
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:
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()
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']
datetime
module to handle times and dates.
>>> 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
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: