Introduction

Goals

This guide will explain some basic python concepts through a series of exercises. However, it’s far from complete and cannot teach you Python. You should read the The Python Tutorial and use the Library Reference whenever necessary.

Humble Beginnings

You don’t need type declarations. To create a variable simply assign to it:

width = 10

To use functions from modules use the import keyword:

import math
a = math.sqrt(7)
help(math.sqrt)
print int(a)

The most common data structure in Python is the list (similar to the C++ std::vector, but without type constraints):

x = [1, 2]
a, b = x
assert a == 1
assert b == 2
x.append(3)
print [1, 2, 3]
assert len(x) == 3

Another common data structure is the tuple (an immutable list):

x = (1, 2)
assert x[1] == 2

Lists, tuples and strings are sequences. More information about sequences can be found in Sequence Types.

In contrast with C and Java, Python uses indentation to delimit blocks:

x = 1
if x == 0:
    print 'zero'
elif x % 2:
    print 'odd'
else:
    print 'even'

Indented blocks are always preceded by a statement which ends in a colon (:). You should always use 4 spaces for indentation (PEP8).

Python has a bool() type with two values: True and False. You can also use any sequence as a boolean value in if or while conditions (empty sequences are False, non-empty sequences are True).

To iterate over a sequence you can use the for statement:

l = [1, 3, 5]
for x in l:
    print x

If you just want to iterate over a range of integers, you can create with the range() function:

assert range(3) == [0, 1, 2]
assert range(1, 3) == [1, 2]

for i in range(len(l)):
    print "l[%d] = %d" % (i, l[i])

This could be also written as:

for idx, val in enumerate(l):
  print "l[%d] = %d" % (idx, val)

To define a function use def:

def even(x):
    return x % 2 == 0

If you don’t explicitly return from a function, the caller will receive the special value None.

You can have a variable number of arguments:

def csv(*args):
    return ', '.join(args)

print csv('a', 'b', 'c')

You can also call a function with arguments from a list object:

print csv(*['a', 'b', 'c'])

Exercise

Define a function which returns True if a number is prime and False otherwise.

isprime(n)

Unit test:

def test_primes():
    assert not isprime(1)
    assert isprime(2)
    assert isprime(3)
    assert not isprime(4)
    assert isprime(97)

Functional Style

If you want to write code in a functional style, you have access to the usual tools:

However Python also provides list comprehensions to replace map() and filter() with a syntax closer to the mathematical set notation:

f1 = filter(lambda x: x % 2 == 0, range(10))
f2 = [x for x in range(10) if x % 2 == 0]
assert f1 == f2

mf1 = map(lambda x: x*x, filter(lambda x: x % 2 == 0, range(10)))
mf2 = [x*x for x in range(10) if x % 2 == 0]
assert mf1 == mf2

List comprehensions can have multiple for and if clauses:

print [(x, y) for x in range(3) for y in range(3)]

Exercise

Define a function which returns the prime numbers smaller than n.

primesuntil(n)

Unit test:

def test_primesuntil():
    assert primesuntil(10) == [2, 3, 5, 7]

Something Useful

The Python equivalent of C/C++ NULL is None. You should always use the is (or is not) operator to compare things with None. is tests for object identity (think of it as pointer comparison).

You can get a sub-sequence from a sequence using the slice notation:

a = range(10)
assert a[1:3] == range(1, 3)

You can omit one or both ends of the slice range, which means the beginning or the end of the sequence is used:

assert a[:3] == range(3)
assert a[3:] == range(3, 10)
assert a[:] == a

Note that the return value of a slice is a shallow copy:

assert a[:] is not a

Negative indexes count backwards from the end of the sequence:

assert a[-1] == a[9]
assert a[-3:] == range(7, 10)

Exercise

Implement binary search using a recursive function. The function definition should start with:

def bsearch(l, x):

where x is the element being searched and l is the list. The return value must satisfy l[bsearch(l, x)] == x or be None if x is not found in l.

You can use slicing to avoid defining a helper function.

Unit test:

def test_bsearch():
    assert bsearch([], 0) is None
    assert bsearch([0], 0) == 0
    assert bsearch([0], 1) is None
    for i in range(11):
        assert bsearch(range(11), i) == i

Mappings

Another important built-in data type is dict, similar to the C++ std::map or the Java HashMap:

emptydict = {}
specs = {'color': 'black', 'size': 3.5}

If the keys are strings that conform to Python identifier naming rules, you can use the dict constructor to avoid quoting them:

specs = dict(color='black', size=3.5)
assert len(specs) == 2
assert specs['color'] == 'black'

print specs['price']
# raise a KeyError exception if the key is not found
print spec.get('price')
# return None if key is not found

assert 'color' in specs
assert 'price' not in specs
del specs['color']
assert 'color' not in specs
specs['color'] = 'green'
print specs.keys()
print specs.values()

print list(specs.iteritems())
for k, v in specs.iteritems():
    print k, '=', v

You can call a function by specifying the name of some parameters together with their value (keyword arguments):

def print_report(rows, columns, color='red'):
    print "A %s report with %d rows and %d columns" % (color, rows, columns)

print_report(1, 1)
print_report(1, 1, 'black')
print_report(color='blue', columns=10, rows=2)

A function can receive variable keyword arguments (kwargs is a dict):

def map2str(**kwargs):
    tmp = ["%s=%s" % (str(k), str(v)) for k, v in kwargs.iteritems()]
    return ', '.join(tmp)

print map2str(size=10, color='black')

def apply_function(f, *args, **kwargs):
    return f(*args, **kwargs)

Exercise

Write a word counter function.

word_count(text, case_sensitive=True)

The return value should be a dict which maps (whitespace-separated) words to the number of occurrences in text.

Hint: read the documentation for String Methods and dict.

Unit test:

def test_word_count():
    assert word_count("a b c") == dict(a=1, b=1, c=1)
    assert word_count("a b a") == dict(a=2, b=1)
    assert word_count("a b A") == dict(a=1, b=1, A=1)
    assert word_count("a b A", False) == dict(a=2, b=1)