Installation

If you have a Mac or a Windows computer, the easiest way of getting Python together with all the most useful scientific libraries installed is to just install a Python Distribution. You can choose between:

Both of these are one-click installers containing Python and a collection of scientific libraries, including the Ipython Notebook that we use for the lecture.

If you are a Linux user, you may prefer to use the standard package manager to install the required packages. You will need at least python2.7, ipython-notebook, python-numpy, python-scipy, and python-matplotlib.


In [2]:
print 'hello world'


hello world

In [3]:



Out[3]:
42

Basics


The "hello world" program


In [ ]:
print "Hello World!"
  • Python provides both an interactive way to develop code and a way to execute scripts
  • What you do interactively is basically the same thing you (can) do in your scripts
  • Open an editor (gedit) an copy the previous line in a file. Save it with the name hello.py
  • Run it with:

      $ python hello.py

Calculator


In [4]:
2 + 2


Out[4]:
4

In [5]:
4 - 2


Out[5]:
2

In [6]:
2.1 + 2


Out[6]:
4.1

In [7]:
3/2


Out[7]:
1

In [8]:
3.0/2.0


Out[8]:
1.5

In [9]:
2*3


Out[9]:
6

In [10]:
1+2j


Out[10]:
(1+2j)

In [11]:
(3.0*10.0 - 25.0)/5.0


Out[11]:
1.0

In [12]:
3.085e18*1e6


Out[12]:
3.085e+24

Declaring variables


In [15]:
t = 1.0  
a = 9.8 
s = 0.5*a*(t**2)
print s


4.9

In-place operators


In [17]:
x = 1
x = x + 3
x


Out[17]:
4

In [ ]:
x *= 5
x

Comparisons


In [19]:
x1 = 10
x2 = 10

In [20]:
x1 == x2


Out[20]:
True

In [21]:
x1 < 3


Out[21]:
False

In [22]:
x1 >= 10


Out[22]:
True

In [25]:
x3 = 12
x1 < 11 or 11 >= x3


Out[25]:
True

Strings


In [26]:
x = "spam"
x


Out[26]:
'spam'

In [27]:
print "hello\nworld!\tI said."


hello
world!	I said.

In [28]:
"hello" == 'hello'


Out[28]:
True

In [30]:
"hello" > "hallo"


Out[30]:
True

In [34]:
"hello" > "bike"
# this is a comment
def myfunc(x):
    """ Prints x
    
    :param x: stuff to print
    
    """
    print(x)

In [41]:



Help on function myfunc in module __main__:

myfunc(x)
    Prints x
    
    :param x: stuff to print


In [32]:
y = """Multiline string are
in triple quotes
      Indentation is preserved!
"""
print y


Multiline string are
in triple quotes
      Indentation is preserved!


In [ ]:
s = "hello" ; e = "world"
print s + e

In [42]:
s = 'hello'
len(s)


Out[42]:
5

In [43]:
s[0]


Out[43]:
'h'

In [44]:
s[-1]


Out[44]:
'o'

In [45]:
s[1:3]


Out[45]:
'el'

In [46]:
s[2:]


Out[46]:
'llo'

In [47]:
x = float('3.2')
y = 4
y+x


Out[47]:
7.2

In [51]:
y + float('3.2')


Out[51]:
7.2

Lists

  • A ordered sequence of objects

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


Out[52]:
[1, 2, 3, 4]

In [54]:
l2 = [1, "hello", "x", 1/3., 4 > 2, l]
l2


Out[54]:
[1,
 'hello',
 'x',
 0.3333333333333333,
 True,
 [1, 'hello', 'x', 0.3333333333333333, True]]

In [55]:
l[0]


Out[55]:
1

In [56]:
l[-2]


Out[56]:
0.3333333333333333

In [60]:
l[1:3:1]


Out[60]:
[1, 2]

In [59]:
l = range(11)
l


Out[59]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [61]:
l[0:8:2]


Out[61]:
[0, 2, 4, 6]

In [64]:
l[::66]


Out[64]:
[0]

In [66]:
l


Out[66]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [67]:
l[0] = "world"
l


Out[67]:
['world', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [69]:
l.sort()
l


Out[69]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 'world']
  • Concatenate lists with + operator:

In [70]:
l2 = ['x', 'y', 'z']
long_l = l + l2
long_l


Out[70]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 'world', 'x', 'y', 'z']

In [71]:
l = [10, 7, 9, 1, 5]
l.sort()
l


Out[71]:
[1, 5, 7, 9, 10]

Dictionaries

  • A table that maps keys to values

In [72]:
tel = {'John': 7192, 'Jim': 9871, 'Jan': 1253}
tel


Out[72]:
{'Jan': 1253, 'Jim': 9871, 'John': 7192}

In [75]:
tel['John']


Out[75]:
7192

In [76]:
tel['Marc'] = 2345
tel


Out[76]:
{'Jan': 1253, 'Jim': 9871, 'John': 7192, 'Marc': 2345}

In [77]:
tel.keys()


Out[77]:
['Jim', 'Jan', 'John', 'Marc']

In [87]:
tel[[3,4,5]] = 'ladia'


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-87-8b33d4a63747> in <module>()
----> 1 tel[[3,4,5]] = 'ladia'

TypeError: unhashable type: 'list'

In [85]:
tel


Out[85]:
{'Jan': 1253, 'Jim': 9871, 'John': 7192, 'Marc': 2345, (3, 4, 5): 'ladia'}

In [ ]:
'John' in tel

In [ ]:
'Sam' in tel

Sets

  • An unordered collection of unique elements
  • In contrast to lists where finding an element takes O(n), look-up happens in O(1)
  • Like dictionaries but only with keys

In [90]:
myset = set(['a', 333, 'b', 'a'])
myset


Out[90]:
{333, 'a', 'b'}

In [ ]:
'a' in myset

In [ ]:
222 in myset

Logical flow control

  • if...elif...else
  • for ... in ...
  • while ...

If...elif...else


In [91]:
if 2*2 == 5:
    print 'I know that!'
  • Blocks are delimited by indentation (4 spaces)

In [93]:
if 2*2 == 4:
     print 'I know that!'


I know that!

In [94]:
if 2*2 == 4:
    print 'I know that'
     print 'Wrong indentation'


  File "<ipython-input-94-3619f5ea585d>", line 3
    print 'Wrong indentation'
    ^
IndentationError: unexpected indent

In [96]:
if 2*2 == 4:
    print 'I know that'
print 'This closes the block'


I know that
This closes the block

In [98]:
x = 55
if x > 0:
    print "positive"
elif x == 0:
    print "zero"
elif x == 55:
    print '55'
else:
    print "negative"


positive

In [100]:
x = 10
y = 20
if x < 0 or y < 100:
    print "yes"
else:
    print "no"


yes

In [ ]:
y = 20
x = y+2 if y < 10 else 100
print x

for ... in ...


In [101]:
for i in range(10):
    print i


0
1
2
3
4
5
6
7
8
9

In [102]:
for i in [0,1,2]:
    print i+2


2
3
4

In [103]:
l = ['x', 10, {'Mark': 1012}]
for francis in l:
    print francis


x
10
{'Mark': 1012}

In [104]:
tel_book = {'Jan': 1253, 'Jim': 9871, 'John': 7192}
for name in tel_book:
    print name, 'telephone number is:', tel_book[name]


Jan telephone number is: 1253
Jim telephone number is: 9871
John telephone number is: 7192

In [116]:
l = [(3,5), (4, 'per'), 5, 6]
for x, y in l:
   print x, y


3 5
4 per
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-116-22023028087e> in <module>()
      1 l = [(3,5), (4, 'per'), 5, 6]
----> 2 for x, y in l:
      3    print x, y

TypeError: 'int' object is not iterable

In [113]:
l = [3,4,5,6]
counter = 0
for value in l:
    l[counter] = value +2
    counter += 1
l


Out[113]:
[5, 6, 7, 8]

In [111]:
for index, name in enumerate(tel_book):
    print index, name


0 Jan
1 Jim
2 John

In [ ]:
for index, obj in enumerate(l):
    print index, obj
  • For loop can be executed implicitly in list comprehensions:

In [ ]:
squares = [x**2 for x in range(10)]
squares

In [ ]:
squares = []
for i in range(10):
    value = i**2
    squares.append(value)

print squares

In [ ]:
squares = [x**2 for x in range(10) if x**3 < 50]
squares

In [ ]:
squares = []
for x in range(10):
    val = x**2
    if x**3 < 50:
        squares.append(val)

print squares

while ...


In [117]:
# find all odd numbers whose square is smaller than 10000
# and whose cube is greater than 500
interesting_numbs = []
x = 0
while x**2 < 1e4:
    if (x % 2 != 0) and (x**3 > 500):
        interesting_numbs.append(x)
    x += 1

print interesting_numbs


[9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99]

In [ ]:
# throw random numbers until we get one smaller than 0.2
from random import random
counter = 0
while True:
    x = random()
    counter += 1
    if x < 0.04:
        break

print 'After', counter, 'trials, I got', x

Defining functions


In [128]:
def double_and_z(x, z=10):
    """Return twice the input
    
    :param x: the value to be doubled
    
    :return: twice the amount of x
    
    """
    # maybe use + instead of * ?
    y = x*2 + z
    return y

In [132]:
z = double_and_z(z=55, 10)
print z


  File "<ipython-input-132-28b2f3faf93c>", line 1
    z = double_and_z(z=55, 10)
SyntaxError: non-keyword arg after keyword arg

In [120]:
double('hello world!')


Out[120]:
'hello world!hello world!'

In [121]:
double(2+1j)


Out[121]:
(4+2j)

In [ ]:
double()

In [ ]:
def double_improved(x, method='*'):
    """Return twice the input.
       
    :param x: the value to be doubled
    
    :param method: 
    
        *optional* argument specifying  
        the method to double `x`
    
    :return: twice the amount of x
    
    :raises: 
    
        ValueError in case the chosen method is not supported
    
    """
    print 'Doubling using', method
    if method == '*':
        return x*2
    elif method == '+':
        return x+x
    else:
        raise ValueError('Method '+method+' not known!')

In [ ]:
double_improved(2)

In [ ]:
double_improved(3, method='+')

In [ ]:
double_improved('x')

In [ ]:
double_improved(10, '*')

In [ ]:
double_improved(1, '/')

In [ ]:
double({'a':1})
  • functions are objects like all others: you can pass functions as arguments to other functions!

In [ ]:
def multiply(x, y):
    """Mutiply x by y"""
    return x*y

def double_generic(x, method=multiply):
    """Return twice the input.
       
    :param x: the value to be doubled
    
    :param method: 
    
        *optional* argument, the actual function
        that is applied to `x`
    
    :return: twice the amount of x
    
    """
    print 'Doubling using', method
    return method(x, 2)

In [ ]:
double_generic(10)

In [ ]:
def donothing(x, y):
    """This function is useless"""
    return x

In [ ]:
double_generic(10, method=donothing)
  • the string after definition is the help text of your function

In [ ]:
help(double_generic)

In [123]:
help(enumerate)


Help on class enumerate in module __builtin__:

class enumerate(object)
 |  enumerate(iterable[, start]) -> iterator for index, value of iterable
 |  
 |  Return an enumerate object.  iterable must be another object that supports
 |  iteration.  The enumerate object yields pairs containing a count (from
 |  start, which defaults to zero) and a value yielded by the iterable argument.
 |  enumerate is useful for obtaining an indexed list:
 |      (0, seq[0]), (1, seq[1]), (2, seq[2]), ...
 |  
 |  Methods defined here:
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  next(...)
 |      x.next() -> the next value, or raise StopIteration
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T


In [122]:
double_generic?


Object `double_generic` not found.
  • Methods are functions attached to objects

In [ ]:
l = [3, 1, 2]
l.sort()
l

In [ ]:
"hello world".split()

In [ ]:
for num, word in enumerate("hello world. I am here".split()):
    print "Word number",num, ':', word

Introspection

  • by hitting TAB you can inspect the methods of any object

In [127]:
s = "hello world" # hitting TAB will show:
s.replace('hello', 'good-bye')


Out[127]:
'good-bye world'
s.capitalize  s.format      s.isupper     s.rindex      s.strip
s.center      s.index       s.join        s.rjust       s.swapcase
s.count       s.isalnum     s.ljust       s.rpartition  s.title
s.decode      s.isalpha     s.lower       s.rsplit      s.translate
s.encode      s.isdigit     s.lstrip      s.rstrip      s.upper
s.endswith    s.islower     s.partition   s.split       s.zfill
s.expandtabs  s.isspace     s.replace     s.splitlines  
s.find        s.istitle     s.rfind       s.startswith  

In [ ]:
help(s.replace)

In [ ]:
s = "hello world"
s.replace("hello", "go away")

Scripts & Modules

  • Let us first write a script, that is a file with a sequence of instructions that are executed each time the script is called.

    The extension for Python files is .py. Write or copy-and-paste the following lines in a file called weather.py


In [ ]:
things = 'day, weather, life'
qualities = ['bad', 'really bad', 'terrible']
for thing in things.split(','):
    for quality in qualities:
        print 'This', thing.strip(), 'is', quality

message_in_the_bottle = "Euthanasia!"
print "You want:", message_in_the_bottle
  • You can execute the script interactively in ipython by running

      %run weather.py
    
    

    The local variables are available


In [ ]:
%run weather.py

In [ ]:
message_in_the_bottle
  • ...or you can execute the script as a standalone program by running in a terminal

      $python test.py
  • Create your own collection of functions: a module

  • Put the following functions in test.py


In [ ]:
def scream(x):
    return x.upper()

def whisper(x):
    return x.lower()

In [ ]:
import test
print test.scream('Is there anybody here?')
print test.whisper('I LIKE CAPS!')

I/O: Read & Write Files


In [ ]:
fh = open('lorem.txt', 'r')

In [ ]:
for line in fh:
    print line[:10], '...',
    words = line.split()
    print len(words)
  • after iterating on the lines, we are located at the end of file:

In [ ]:
for line in fh:
    print "Still more lines!"
else:
    print "No lines!"

In [ ]:
# rewind
fh.seek(0)
count = 0
for line in enumerate(fh):
    count += 1
print count

In [ ]:
fh.close()

In [ ]:
fhw = open("tobewritten.txt", 'w+')

In [ ]:
for i in range(10):
    fhw.write(str(i)+"\n")
fhw.flush()

In [ ]:
fhw.seek(0)
content = fhw.read()

In [ ]:
content

In [ ]:
content.splitlines()

In [ ]:
fhw.seek(0)
content = fhw.read()
lines = content.splitlines()
int_list = [int(i) for i in lines]
print int_list

In [ ]:
fhw.close()

Standard Library

The Batteries included!

  • from a web server: SimpleHTTPServer ... to converting between color systems: colorsys
  • from profiling: cProfile ... to secure hash and digest algorithms hashlib
  • from threads: threading to subprocesses: subprocess
  • Go and see yourself the list of modules in the Standard Library: http://docs.python.org/py-modindex.html

pickle: The one battery you will need for sure – Python object serialization.


In [144]:
from pickle import dump, load

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

In [146]:
dumpfile = open('dump.pic', 'w')

In [147]:
dump(l, dumpfile)

In [148]:
dumpfile.close()

In [149]:
dumpfile = open('dump.pic', 'r')

In [150]:
x = load(dumpfile)

In [151]:
x


Out[151]:
[1, 2, 3]

Debugging


In [ ]:
def print_fourth_element(mylist):
    print 'The forth element is:'
    print mylist[3]


def main():
    a = 42
    b = 'lorem ipsum'
    c = 4+4j

    mylist = [a,b,c]
    print_fourth_element(mylist)

main()

In [ ]:
%debug

In [ ]:
import pdb

def lets_debug_this(idx):
    pdb.set_trace()
    print ('I am in iteration %d' % idx)

for irun in range(4):
    lets_debug_this(irun)

Python is great for Object Oriented Programming (but out of the scope of this tutorial)


In [ ]:
class MyClass(object):
    def __init__(self, name='Custom Class'):
        self.name = name
    
    def print_name(self):
        print 'My name is ' + self.name
        
myobject = MyClass('Example Object')
myobject.print_name()

In [142]:
import this


The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In [ ]: