Introduction to Python!

Python Files and Modules

Python Files

Structure of the Code file

  • Code files end with ".py":

      myprogram.py
  • Every line is a Python statement (or part thereof).

      * comment line start with `#`

Run Python Program from command line

  • Execute with python interpreter

      $ python myprogram.py        
  • Direct use on UNIX systems

    • define the path to the interpreter on the first line of the program as comment

      #!/usr/bin/env python

- If setting the executable flag of the file, we can run the program directly in the shell:

    $ myprogram.py

Variables and Types in Python

Syntax and Naming Convention

  • Variable names contain
    • alphanumerical characters a-z, A-Z, 0-9
    • some special characters such as _.
  • Convention
    • variable names start with a lower-case letter
    • Class names start with a capital letter.
    • Visible variable names must start with a letter.
    • Hidden variables and class variables start with a double underscore__
  • Python keywords not usable as variable names:
and, as, assert, break, class, continue, def, del, elif, else, except, 
exec, finally, for, from, global, if, import, in, is, lambda, not, or,
pass, print, raise, return, try, while, with, yield

  • Python's Type system is dynamic, implicit and strong.

Assignment

The assignment operator in Python is =.

The type is determined dynamically on assignment. No explicit definition


In [ ]:
# variable assignments

myInt = 1
myFloat = 12.2
myString = "Hallo"
myBoolean = True

The type is derived form the value it was assigned (duck-typing)


In [ ]:
type(myFloat)

If we assign a new value to a variable, its type can change.


In [ ]:
myFloat = 1

type(myFloat)

If we try to use a variable that has not yet been defined we get an NameError:


In [ ]:
print(myChar)

Basictypes


In [ ]:
# integers
x = 1
type(x)

In [ ]:
# float
x = 1.0
type(x)

In [ ]:
# boolean
b1 = True
b2 = False

type(b1)

We can also use the isinstance method for testing types of variables:


In [ ]:
isinstance(x, float)

Basic Data Structures

Python provides a large set of fast, easy to use data structures. In particular

  • Strings
  • List (mutable arrays)
  • Tupel (inmutable Lists)
  • Dictionaries (Maps)

Built-in data structures are implemented in C.

Strings

Strings are the variable type that is used for storing text messages as array of characters/bytes.


In [ ]:
characters = "Complex Systems Engineering"

type(characters)

In [ ]:
char = "C"

type(char)

In [ ]:
# length of the string: the number of characters
len(char)

In [ ]:
s = "Hello world"

In [ ]:
# replace a substring in a string with somethign else
s2 = s.replace( "world", "test")
print(s2)

We can index a character in a string using []:

Note: Indexing start at 0!


In [ ]:
s[0]

Basic Indexing

We can extract a part of a string using the syntax [start:stop], which extracts characters between index start and stop:


In [ ]:
s[0:5]

If we omit either (or both) of start or stop from [start:stop], the default is the beginning and the end of the string, respectively:


In [ ]:
s[:5]

In [ ]:
s[6:]

In [ ]:
s[:]

Type casting


In [ ]:
x = "80"
y = "20"

print(x, type(x), y, type(y))

In [ ]:
u = x + y

print(u, type(u))

In [ ]:
u = int(x) + int(y)

print(u, type(u))

In [ ]:
x = "80.0"

x = int(x)

Operators and Comparisons

Most operators and comparisons in Python work as one would expect. We will briefly outline the following operators

  • Arithmetic Operators
  • Boolean Operators
  • Comparison Operators

Arithmetic Operators

  • Arithmetic operators +, -, *, /, // (integer division), '**' power

In [ ]:
1 + 2, 1 - 2, 1 * 2, 1 / 2

In [ ]:
1.0 + 2.0, 1.0 - 2.0, 1.0 * 2.0, 1.0 / 2.0

In [ ]:
# Integer division of float numbers
3.0 // 2.0

In [ ]:
# Note! The power operators in python isn't ^, but **
2 ** 2

Boolean Operators

  • The boolean operators are spelled out as words and, not, or.

In [ ]:
True and False

In [ ]:
not False

In [ ]:
True or False

Comparison Operators

  • Comparison operators >, <, >= (greater or equal), <= (less or equal), == equality, is identical.

In [ ]:
2 > 1, 2 < 1

In [ ]:
2 > 2, 2 < 2

In [ ]:
2 >= 2, 2 <= 2

In [ ]:
# equality
[1,2] == [1,2]

In [ ]:
# objects identical?
l1 = l2 = [1,2]

l1 is l2

In [ ]:
[1,2] is [1,2]

String formatting examples


In [ ]:
print("str1", "str2", "str3")  # The print statement concatenates strings with a space

In [ ]:
print("str1", 1.0, False, -1j)  # The print statements converts all arguments to strings

In [ ]:
print("str1" + "str2" + "str3") # strings added with + are concatenated without space

In [ ]:
a = 5

print ("Hallo" + a)

List

Lists are very similar to strings, except that each element can be of any type.

The syntax for creating lists in Python is [...]:


In [ ]:
l = [1,2,3,4]

print(type(l))
print(l)

See help(list) for more details, or read the online documentation

List Indexing

We can use the same slicing techniques to manipulate lists as we could use on strings:


In [ ]:
print(l)

print(l[1:3])

print(l[::2])

Noe: Indexing starts at 0!


In [ ]:
l[0]

Heterogeneous Types and Nesting

Elements in a list do not all have to be of the same type:


In [ ]:
l = [1, 'a', 1.0, 1-1j]

print(l)

Python lists can be inhomogeneous and arbitrarily nested:


In [ ]:
nested_list = [1, [2, [3, [4, [5]]]]]

nested_list

Lists and flow control

Lists play a very important role in Python, and are for example used in loops and other flow control structures (discussed below). There are number of convenient functions for generating lists of various types, for example the range function:


In [ ]:
start = 10
stop = 30
step = 2

range(start, stop, step)

In [ ]:
# in python 3 range generates an iterator, which can be converted to a list using 'list(...)'. It has no effect in python 2
list(range(start, stop, step))

In [ ]:
list(range(-10, 10))

In [ ]:
s = "some string"

In [ ]:
# convert a string to a list by type casting:

s2 = list(s)

s2

In [ ]:
# sorting lists
s2.sort()

print(s2)

Adding, inserting, modifying, and removing elements from lists


In [ ]:
# create a new empty list
l = []

# add an elements using `append`
l.append("A")
l.append("d")
l.append("d")

print(l)

We can modify lists by assigning new values to elements in the list. In technical jargon, lists are mutable.


In [ ]:
l[1] = "p"
l[2] = "p"

print(l)

In [ ]:
l[1:] = ["d", "d"]

print(l)

Insert

Insert an element at an specific index using insert


In [ ]:
l.insert(0, "i")
l.insert(1, "n")
l.insert(2, "s")
l.insert(3, "e")
l.insert(4, "r")
l.insert(5, "t")

print(l)

Remove

Remove first element with specific value using 'remove'


In [ ]:
l.remove("d")

print(l)

Remove an element at a specific location using del:


In [ ]:
del l[7]
del l[6]

print(l)

Question

Print the length of a given list like [9,5,1,2]


In [ ]:
#Write your solution here

Execute the next cell to see a sample solution


In [ ]:
print("""print(len([9,5,1,2])""")

Check if 3 belong to this list [6,9,5,3]


In [ ]:
#Write your solution here

Execute the next cell to see a sample solution


In [ ]:
print("""     3 in [6,9,5,3]

The result of this instruct is boolean """)

Tuples

Tuples are like lists, except that they cannot be modified once created, that is they are immutable.

In Python, tuples are created using the syntax (..., ..., ...), or even ..., ...:


In [ ]:
point = (10, 20)

print(point, type(point))

In [ ]:
point = 10, "Olaf"

print(point, type(point))

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

Unpacking tuples

We can unpack a tuple by assigning it to a comma-separated list of variables:


In [ ]:
x, y = point

print("x =", x)
print("y =", y)

Tuples are Inmutable

If we try to assign a new value to an element in a tuple we get an error:


In [ ]:
point[0] = 20

Dictionaries

Dictionaries are also like lists, except that each element is a key-value pair. The syntax for dictionaries is {key1 : value1, ...}:


In [ ]:
params = {"key1" : 1.0,
          "key2" : 2.0,
          "key3" : 3.0,}

print(type(params))
print(params.keys())
print(params.values())
print(params)

In [ ]:
print("key1 = " + str(params["key1"]))
print("key3 = " + str(params["key3"]))

In [ ]:
params["key1"] = "A"
params["key2"] = "B"

# add a new entry
params["key4"] = "D"

print("key1 = " + str(params["key1"]))
print("key2 = " + str(params["key2"]))
print("key3 = " + str(params["key3"]))
print("key4 = " + str(params["key4"]))

Control Flow

Conditional statements: if, elif, else

The Python Syntax for conditional execution of code use the keywords if, elif (else if), else:


In [ ]:
statement1 = True
statement2 = False

if statement1:
    print("statement1 is True")

elif statement2:
    print("statement2 is True")
    
else:
    print("statement1 and statement2 are False")

Blocks are defined by indention

For the first time, here we encounted a peculiar and unusual aspect of the Python programming language: Program blocks are defined by their indentation level.

Compare to the equivalent JAVA code:

if (statement1)
{
    System.out.println("statement1 is True\n");
}
else if (statement2)
{
    System.out.println("statement2 is True\n");
}
else
{
    System.out.println("statement1 and statement2 are False\n");
}

In C blocks are defined by the enclosing curly brakets { and }. And the level of indentation (white space before the code statements) does not matter (completely optional).

But in Python, the extent of a code block is defined by the indentation level (usually a tab or say four white spaces). This means that we have to be careful to indent our code correctly, or else we will get syntax errors.

IF Example - Blocks by indention


In [ ]:
statement1 = statement2 = True

if statement1:
    if statement2:
        print("both statement1 and statement2 are True")

In [ ]:
# Bad indentation!
if statement1:
    if statement2:      
                print("both statement1 and statement2 are True")  # this line is not properly indented

In [ ]:
statement1 = True 

if statement1:
    print("printed if statement1 is True")
    
    print("still inside the if block")

In [ ]:
if statement1:
    print("printed if statement1 is True")
    
print("now outside the if block")

Loops

In Python, loops can be programmed in a number of different ways. The most common is the for loop, which is used together with iterable objects, such as lists. The basic syntax is:

for loops:


In [ ]:
for x in range(6): # by default range start at 0
    print(x)

In [ ]:
for x in range(-3,3):
    print(x)

In [ ]:
myList = [1,2,3]

for i in range(len(myList)):
    print(myList[i])

In [ ]:
for item in myList:
    print(item)

Counting for loops

The for loop iterates over the elements of the supplied list, and executes the containing block once for each element. Any kind of list can be used in the for loop. For example:


In [ ]:
strList = ["complex", "systems", "engineering"]

for word in strList:
    print(word)

Sometimes it is useful to have access to the indices of the values when iterating over a list. We can use the enumerate function for this:


In [ ]:
for index, word in enumerate(strList):
    print(index, word)

Note: range(4) does not include 4 !

Iterating over Dictionaries

To iterate over key-value pairs of a dictionary:


In [ ]:
for key, value in params.items():
    print(key + " = " + str(value))

    
#for key in params.keys():
#    print(key + " = " + str(params[key]))

List comprehensions: Creating lists using for loops

A convenient and compact way to initialize lists:


In [ ]:
l1 = [x**2 for x in range(0,5)]

print(l1)

List comprehensions can be conditional (and hence very powerful especially when working with data structures!)


In [ ]:
allCars = [("mercedes", 10000), ("bmw", 20000), ("toyota", 8000), ("vw", 6000)]


myCars = [car for car in allCars if car[1] <= 8000]

print(myCars)

In [ ]:
# find the prices of all cars, that have a "w" in their brand

while loops


In [ ]:
i = 0

while i < 5:
    print(i)
    
    i = i + 1
    
    #i += 1
    
print("done")

Note that the print("done") statement is not part of the while loop body because of the difference in indentation.

Functions

A function in Python is defined using the keyword def, followed by a function name, a signature within parenthises (), and a colon :. The following code, with one additional level of indentation, is the function body.


In [ ]:
def func0():   
    print("Without Parameter")
          
def func1(someString):
    print(someString)

Because Python has a dynamic type system, func0 does not need to specify the type of the return values nor the parameters.


In [ ]:
func0()

func1("with parameter")

Documenting a Function

Optionally, but highly recommended, we can define a so called "docstring", which is a description of the functions purpose and behaivor. The docstring should follow directly after the function definition, before the code in the function body.


In [ ]:
def func1(s):
    """
    Print a string 's' and tell how many characters it has 
    """
    
    print(s + " has " + str(len(s)) + " characters")

In [ ]:
help(func1)

In [ ]:
func1("test")

In [ ]:
func1(5)

Python has a dynamic and strong type system

Returning values

Functions that returns a value use the return keyword to return any object or function:


In [ ]:
def square(x):
    """
    Return the square of x.
    """
    return x ** 2

In [ ]:
square(4)

Returning Multiple Values

We can return multiple values from a function using tuples (see above):


In [ ]:
def powers(x):
    """
    Return a few powers of x.
    """
    return x ** 2, x ** 3, x ** 4

In [ ]:
resultOfPowers = powers(3)

print(type(resultOfPowers))
print(resultOfPowers)
print(resultOfPowers[0])

In [ ]:
x2, x3, x4 = powers(3)

print(x3)

Default argument and keyword arguments

In a definition of a function, we can give default values to the arguments the function takes:


In [ ]:
def myfunc(x, p=2, debug=False):
    
    if debug:
        print("evaluating myfunc for x = " + str(x) + " using exponent p = " + str(p))
        
    return x**p

If we don't provide a value of the debug argument when calling the the function myfunc it defaults to the value provided in the function definition:


In [ ]:
myfunc(5)

In [ ]:
myfunc(5, 3, True)

Keyword Argument

If we explicitly list the name of the arguments in the function calls, they do not need to come in the same order as in the function definition.

This is called keyword arguments, and is often very useful in functions that take a lot of optional arguments.


In [ ]:
myfunc(p=3, debug=True, x=7)

Unnamed functions (lambda function)

In Python we can also create unnamed functions, using the lambda keyword:


In [ ]:
f1 = lambda x: x**2
    
# is equivalent to 

def f2(x):
    return x**2

In [ ]:
f1(2), f2(2)

Practice

Exercise 1

Write a Python function that can calculate the length of a given string


In [ ]:
def s_length(string):
    #write your code here

Execute the next cell to test your solution


In [ ]:
import sys
import traceback


try:
    assert s_length("python") == 6
    print("success")
except AssertionError:
    print('try again')
    
solution ="""def s_length(string):
    c = 0
    for char in string:
        c += 1
    return c"""

Execute the next cell to see the solution


In [ ]:
print(solution)

Exercise 2

Write a function that print a single string from two strings, separated by a space and switch the first character of each string.

Sample String : 'abc', 'xyz' Expected Result : 'xbc ayz'


In [ ]:
def char_mix(a, b):
    #write your code here

Execute the next cell to test your solution


In [ ]:
import sys
import traceback


try:
    assert char_mix("abc","jhg") == "jbc ahg"
    print("success")
except AssertionError:
    print('try again')
    
sol ="""def char_mix(a, b):
  mix_a = b[:1] + a[1:]
  mix_b = a[:1] + b[1:]
  return mix_a + ' ' + mix_b"""

Execute the next cell to see the solution


In [ ]:
print(sol)

Classes

Classes are the key features of object-oriented programming.

A class is a structure for representing an object and the operations that can be performed on the object.

A class can contain attributes (variables) and methods (functions).

A class is defined using the class keyword plus a number of class method definitions (a function in a class).

  • Each class method should have an argurment self as it first argument. This object is a self-reference.

  • Some class method names have special meaning, for example:


In [ ]:
class Point:
    """
    Simple class for representing a point in a Cartesian coordinate system.
    """
    
    def __init__(self, x, y):
        """
        Create a new Point at x, y.
        """
        self.x = x
        self.y = y
        
    def translate(self, dx, dy):
        """
        Translate the point by dx and dy in the x and y direction.
        """
        self.x += dx
        self.y += dy
        
    def __str__(self):
        return("Point at [%f, %f]" % (self.x, self.y))

Instance Creation

To create a new instance of a class:


In [ ]:
p1 = Point(0, 0) # this will invoke the __init__ method in the Point class

print(p1)         # this will invode the __str__ method

To invoke a class method in the class instance p:


In [ ]:
p2 = Point(1, 1)

p1.translate(0.25, 1.5)

print(p1)
print(p2)

Note that calling class methods can modifiy the state of that particular class instance, but does not effect other class instances or any global variables.

That is one of the nice things about object-oriented design: code such as functions and related variables are grouped in separate and independent entities.

Python Modules

Overview

  • Modules group Python functions
  • Modules are files with containing Python code (e.g. myprogram.py)
  • Using Modules requires to import them first using the import statement
  • Scope: Import a module to the current namespace, defined in its own namespace or used as module.function

The Python Standard Library is a large collection of modules that provides cross-platform implementations of common facilities such as access to the operating system, file I/O, string management, network communication, and much more.

References

Module import

For example, to import the module math, which contains many standard mathematical functions, we can do:


In [ ]:
import math

Imports the whole module and makes it available under the moduls namespace. For example, we can do:


In [ ]:
x = math.cos(2 * math.pi)

print(x)

**Note**: Contrary to Java a Python file can contain classes, variables, function and main code. The filename defines the module name and the namespace to access the functions
  • Caveat: possible namespace conflicts in large programs

Import selected Functions into the current Namespace

Selective import of function from a module


In [ ]:
from math import cos, pi

x = cos(2 * pi)

print(x)

Import a Module in current Namespace

  • Goal: avoid writing the prefix module. by importing all symbols (functions and variables) of one module into the current namespace

In [ ]:
from math import *

x = cos(2 * pi)

print(x)

Changing the Name/Namespace of a Functions/Modules at Import

Names of variables, functions and the namespace of moduls can be changed at import using the as keyword


In [ ]:
from math import cos as c
from math import pi as p
import math as m

x = c(2 * p)
y = m.cos(2 * m.pi)
print (x,y)

Caveat: Readability may suffer.

Looking at what a module contains

Once a module is imported, we can list the symbols it provides using the dir function:


In [ ]:
import math

print(dir(math))

Getting Help on a Function

And using the function help we can get a description of each function (almost .. not all functions have docstrings, as they are technically called, but the vast majority of functions are documented this way).


In [ ]:
help(math.log)

In [ ]:
log(10)

In [ ]:
log(10, 2)

Getting Help on a Module

Use help function directly on modules:

help(math) 

Some very useful modules form the Python standard library are

  • os
  • sys
  • math
  • shutil
  • re
  • subprocess
  • multiprocessing
  • threading.

A complete lists of standard modules for Python 2 and Python 3 are available at http://docs.python.org/2/library/ and http://docs.python.org/3/library/, respectively.

Matplotlib

matplotlib.pyplot is a collection of command style functions that make matplotlib work like MATLAB


In [ ]:
import matplotlib.pyplot as plt
plt.plot([0,1,2,3,4])
plt.ylabel('some numbers')
plt.show()

In [ ]:
a = [0,1,2,3,4]
squared = [x**2 for x in a]

plt.plot(a, squared, 'ro')
plt.ylabel('some numbers')
plt.show()

In [ ]:
import math

def sigmoid(x):
    a = []
    for item in x:
        a.append(1/(1+math.exp(-item)))
    return a

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(-10, 10, 0.2)
sig = sigmoid(x)
plt.plot(x,sig)
plt.axhline(0, color='black')
plt.axvline(0, color='black')
plt.grid(True)
plt.show()

Numpy - Exercise

NumPy enriches the programming language Python with powerful data structures for efficient computation of multi- dimensional arrays and matrices. The implementation is even aiming at huge matrices and arrays. Besides that the module supplies a large library of high-level mathematical functions to operate on these matrices and arrays.


In [ ]:
import numpy as np

Task1

Try to complete the following tasks:


In [ ]:
# create a one-dimensional python list containing 15 integers from 0 to 14

In [ ]:
# create a new numpy array containing the values of the python list

In [ ]:
# reshape the numpy array into a 2-Dimensional matrix with 3 rows and 5 coloumns

In [ ]:
# print the dimensions of the array

In [ ]:
# divide the entire array by 2

In [ ]:
# add another 2 columns to the matrix with the values 0,1,2

In [ ]:
# create two numpy arrays of length 1000, one initialised with only 1's and one with only 0's

In [ ]:
# add random values to each value inside the 0-array

Further reading

Versions


In [ ]:
import sys
import IPython

In [ ]:
print("This notebook was evaluated with: Python %s and IPython %s." % (sys.version, IPython.__version__))

This Notebook is an adaptation of:

Data Science in Python (DSiP) - Programming Basics

by Michael Granitzer (michael.granitzer@uni-passau.de)

based on the following sources

License

This work is licensed under a Creative Commons Attribution 3.0 Unported License