Python Training – Part 1

Part 2 | Part 3 | Part 4 | Part 5

This is the course material for a Python training that I gave while I was working at SPIELO International. My manager kindly gave me permission to publish the material. The material is Copyright © 2008-2011 SPIELO International, licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

The target audience for the trainings were software developers, testers, and mathematicians. Each training session took 3 to 4 hours and consisted mostly of interactive programming, roughly (but not slavishly) following the outline on this page. Depending on the prior programming experience of each group, I made small changes to the trainings as I went along.

Each participant received this tutorial printed to a booklet (12 or 16 pages). Even though I would usually deviate a lot from the exact examples in the handouts, having the handouts frees the participants from taking their own notes and allows them to actively participate in the classroom. I also gave out little exercises at the end of each session to be completed by the participants until the following week.

Advertisement

Note: The training was based on Python 2.x, because that’s what we were using at the time. I would love to update it to Python 3 at some point. Any help with this would be greatly appreciated.

About Python

Python is an interpreted, dynamically-typed, object-oriented programming language. It can be used for writing small, throw-away scripts and large, object-oriented applications alike. Some of Python’s features:

  • Built-in high-level data types
  • Garbage collector
  • Comprehensive standard library and a myriad of add-on libraries on the web
  • Easily extensible with libraries written in other programming languages

Getting Started

Installing

To use Python locally, install these programs:

Running

Python source code has the filename extension “.py”. When Python is installed locally, you can double-click a “.py” file to run the program. You can also run “python.exe <py-file>” from the command line.

Interactive Mode

When you start “python.exe” from the command line without parameters, Python runs in interactive mode. In this mode, you can type Python source code directly on the console and see the results immediately.

If you prefer a GUI, you can run the interactive Python shell using PyCrust (from the wxPython Tools) or the PythonWin IDE. Both provide code completion and other useful features.

Editing/Debugging

To edit and debug Python programs, you can use PythonWin.

For developing larger Python programs consisting of many files, I recommend Eclipse and the PyDev plug-in.

Manuals

When you install Python locally, you can find the Python Manuals, including a tutorial, on the Start menu.

In an interactive Python shell, use the built-in “help” function to display help for any Python object. For example, help(str) prints a list of all methods of str objects.

Use PyCrust to receive IntelliSense-style help on available methods and method parameters.

Hello, World!

Write the following code into a file with the extension “.py” or type the code in an interactive Python shell.

The typical “Hello, World!” program is nearly too simple in Python:

print “Hello, World!”

Let’s make it more interesting:

who = raw_input("Who do you want to greet (default is World): ")
if not who:
    who = "World"
else:
    who = who.capitalize() # make the first character upper-case
print who, "is in da house!", # comma at the end prevents newline
print "Hello, " + who + "!"

Things to note:

  • You don’t declare the data type of variables, you just assign a value (“who”)
  • No curly braces for “if” and “else” blocks: The indentation alone determines where a block ends
  • Strings are objects (“capitalize” method, “+” operator overloaded, etc.). As we’ll see later, everything’s an object in Python.

Built-in Data Types

In the following examples, “>>>” denotes lines that you type in the Python shell and “…” denotes the output.

Note: I recommend PyCrust as an interactive shell, because it has some features that PythonWin lacks. You can paste lines starting with “>>>” into PyCrust when you click “Edit” → “Paste Plus”.

Numbers

There are no big surprises. The operators are more or less the same as in C. Python has built-in support for large integers. Here are a few examples of working with numbers:

>>> (12 + 3) * 47
… 705
>>> 0xff
… 255
>>> 32 / 7.0 * 1.3e-6
… 5.9428571428571423e-006
>>> 2**16
… 65536
>>> _ - (1 << 16)
    # in interactive mode, “_” contains the last printed value,
    # i.e., 65536
… 0
>>> 12**45
… 3657261988008837196714082302655030834027437228032L

Strings

Examples of working with strings:

>>> "Here's a string"
… "Here's a string"
>>> 'This "is" it'
… 'This "is" it'
>>> print "Newlinen"and"ttab"
… Newline
… "and"   tab
>>> "C:\temp"
… 'C:\temp'
>>> r"C:temp"
    # in a raw string ('r' prefix), the backslash is not an escape character
… 'C:\temp'
>>> """Multi-
line string"""
… 'Multi-nline string'
>>> '''Multi-
  line string'''
… ‘Multi-n  line string’

You can convert any object to human-readable form by using the “str” function. The “repr” function has a similar purpose: If possible, it returns a string representation that you can later pass to the “eval” function to turn the string back into an object.

>>> str(5)
… '5'
>>> repr(5)
… '5'
>>> str(3.8)
… '3.8'
>>> repr(3.8)
… '3.7999999999999998'
>>> repr({1: 3, 2: 4})
… '{1: 3, 2: 4}'
>>> eval('{1: 3, 2: 4}')
… {1: 3, 2: 4}

Some useful string methods and operators:

>>> "Hello, " + "World!"
… 'Hello, World!'
>>> "x" * 10
… 'xxxxxxxxxx'
>>> w = '    word  '
>>> w.strip()
… 'word'
>>> w.lstrip()
… 'word  '
>>> w.rstrip()
… '    word'
>>> s = "Edward Kennedy Ellington"
>>> s[1]
… 'd'
>>> s.startswith("Edw")
… True
>>> "Kennedy" in s
… True
>>> s.lower()
… 'edward kennedy ellington'
>>> s.upper().replace("E", "U")
… 'UDWARD KUNNUDY ULLINGTON'

Using the slice notation, you can access sub-strings:

>>> s = "Hello, World!"
>>> s[1:]    # sub-string starting at index 1
… 'ello, World!'
>>> s[:3]    # sub-string up to but not including index 3
… 'Hel'
>>> s[2:5]
… 'llo'
>>> len(s[2:5] == 5 - 2)
… True
>>> s[-1]    # the last character
… '!'
>>> s[:-2]    # everything up to the second-last character
… 'Hello, Worl'

Strings are immutable, i.e., you can’t modify them after they were created. For example, you can’t use the subscript operator “[]” to overwrite characters in the string.

>>> s[1] = 'x'
… TypeError: 'str' object does not support item assignment

The “%” operator provides printf-like functionality:

>>> "%s has the value %i" % ("X", 25)
… 'X has the value 25'
>>> "%s has the value %s" % ("X", 25)
… 'X has the value 25'
>>> val1 = 3
>>> val2 = 8
>>> "%(val1)i and %(val2)i" % locals()
… '3 and 8'

For scanf-like functionality, you should use regular expressions. See the “re” module in the standard library. We’ll cover this in one of the next lessons.

What we didn’t cover: There’s a separate class for Unicode strings. We’ll get back to this in one of the next lessons.

If you’re interested, you can try it out yourself:

>>> u"äöü"
… u'xe4xf6xfc'
>>> u"äöü".encode("utf-8")
… 'xc3xa4xc3xb6xc3xbc'
>>> _.decode("utf-8")
… u'xe4xf6xfc'

Lists

Python has a built-in list data type that can store objects of arbitrary types.

>>> ls = [1, "text", 3, [4, 5]]
>>> ls
… [1, 'text', 3, [4, 5]]
>>> ls[1]
… 'text'
>>> ls[1] = 2
>>> ls
… [1, 2, 3, [4, 5]]
>>> ls[1:3]
… [2, 3]
>>> ls[1:3] = []    # same as del[1:3]
>>> ls
… [1, [4, 5]]
>>> ls[1:2] = [4, 3, 5, 2]
>>> ls
… [1, 4, 3, 5, 2, [4, 5]]
>>> del ls[-1]
>>> ls
… [1, 4, 3, 5, 2]
>>> ls.sort()
>>> ls
… [1, 2, 3, 4, 5]
>>> ls.reverse()
>>> ls
… [5, 4, 3, 2, 1]
>>> ls.append(11)
>>> ls
… [5, 4, 3, 2, 1, 11]
>>> ls.pop()
… 11
>>> ls
… [5, 4, 3, 2, 1]
>>> ls.extend([11, 12, 13])
>>> ls
… [5, 4, 3, 2, 1, 11, 12, 13]

Tuples

You can think of tuples as fixed-length lists. Here are a few examples:

>>> t = (1, 2, "text")
>>> t
… (1, 2, 'text')
>>> len(t)
… 3
>>> t[0]
… 1
>>> t[1] = 5
… TypeError: 'tuple' object does not support item assignment
>>> a, b, c = t
>>> print a, b, c
… 1 2 text
>>> u = a, b
>>> u
… (1, 2)
>>> empty = ()
>>> empty
… ()
>>> singleton = (1,)
>>> singleton
… (1,)
>>> list(singleton)
… [1]
>>> tuple([1, 2, 3])
… (1, 2, 3)
>>> i, (name, age) = (0, ("John", 4))
>>> print i, name, age
… 0 John 4
>>> # BTW, this works with lists just as well:
>>> i, (name, age) = [1, ["Sue", 27]]
>>> print i, name, age
… 1 Sue 27

Dictionaries

Dictionaries are associative containers, i.e., mappings between keys and values. Python dictionaries are implemented as hash tables and can store arbitrary data types. Here are a few examples:

>>> d = {5: 3.2,
>>>      "John": 4,
>>>      (1, 2): [3, 4, 5]}
… {5: 3.2, 'John': 4, (1, 2): [3, 4, 5]}
>>> d[5]
… 3.2
>>> d["John"] = "Doe"
>>> d
… {5: 3.2, 'John': 'Doe', (1, 2): [3, 4, 5]}
>>> d["Jane"] = "Doe"
>>> d
… {5: 3.2, 'John': 'Doe', 'Jane': 'Doe', (1, 2): [3, 4, 5]}
>>> d.keys()
… [5, 'John', 'Jane', (1, 2)]
>>> d.values()
… [3.2, 'Doe', 'Doe', [3, 4, 5]]
>>> d.items()
… [(5, 3.2), ('John', 'Doe'), ('Jane', 'Doe'), ((1, 2), [3, 4, 5])]
>>> d.update({5: 4.8, 7: 3})
>>> d
… [(5, 4.8), ('John', 'Doe'), 7: 3, ('Jane', 'Doe'), ((1, 2), [3, 4, 5])]
>>> d2 = dict([(5, 3.2), ("John", "Doe")])
>>> d2
… {'John': 'Doe', 5: 3.2}
>>> # Dicts can be used with the “%” operator for strings
>>> "My name is %(John)s" % d2
… 'My name is Doe'
>>> del d2["John"]
>>> d2
… {5: 3.2}

Sets

Sets are similar to lists, but their values are unique and unordered. The “set” data type supports operations such as computing the union, difference, and intersection of sets.

>>> s = set([10, 3, 7, 3, 5, 4, 4])
>>> s
… set([10, 3, 4, 5, 7]
>>> s.add(8)
>>> s
… set([3, 4, 5, 7, 8, 10])
>>> s.difference([7, 10, 4])
… set([3, 5, 8])
>>> s.union([3, "Joe"])
… set([3, 4, 5, 7, 8, 10, 'Joe'])
>>> s.intersection([1, 5, 7])
… set([5, 7])

Control Structures

If Statements

This is an example for an if-elif-else statement:

if x == 5:
    This()
    AndThat()
elif y > 3 and z != 4:
    Other()
else:
    SomethingElseEntirely()

This, of course, is the same as:

if x == 5:
    This()
    AndThat()
else:
    if y > 3 and z != 4:
        Other()
    else:
        SomethingElseEntirely()

If the Boolean expression gets too long, you might want to introduce a line break. The following attempt, however, would result in a syntax error:

if y > 3
  and z != 4:
    …

You must either use the line continuation character “”:

if y > 3 
  and z != 4:
    …

Or enclose the expression in parentheses:

if (y > 3
  and z != 4):
    …

Python does not check the indentation inside parentheses, brackets (as used for lists), and curly braces (as used for dicts), so you can always insert line breaks inside those.

While Loops

Here’s an example for a “while” loop in Python:

x = 1
while x < 100:
    print x
    x *= 3

Note: There is no equivalent to “do-while” loops in Python.

For Loops

In Python, “for” loops are used exclusively to iterate over sequences. If you want something like “for (int i = 0; i < 10; ++i)”, use the “xrange” function, which returns a sequence of integers:

for i in xrange(10):
    print i,

Output: 0 1 2 3 4 5 6 7 8 9

ls = [6, 1, 5, 3, 7]
for x in ls:
    print x,

for x in sorted(ls):
    print x,

for x in reversed(ls):
    print x,

Output:

6 1 5 3 7
1 3 5 6 7
7 3 5 1 6

d = {1: 10, 3: 30, 5: 50}
for k in d:
    print k,

Output: 1 3 5

d = {1: 10, 3: 30, 5: 50}
for k, v in d.iteritems():
    print "%i = %i" % (k, v)

Output:

1 = 10
3 = 30
5 = 50

people = [("John", 4),
           ("Sue", 27),
           ("Frank", 15),
           ("Clara", 8)]
for i, (name, age) in enumerate(people):
    print "%i: %s is %i years old" % (i, name, age)

Output:

0: John is 4 years old
1: Sue is 27 years old
2: Frank is 15 years old
3: Clara is 8 years old

The “break” and “continue” keywords known from C exist in Python as well.

people = [("John", 4),
           ("Sue", 27),
           ("Frank", 15),
           ("Clara", 8)]
for i, (name, age) in enumerate(people):
    if age > 25:
        continue
    print "%i: %s is %i years old" % (i, name, age)
    if age == 15:
        break

Output:

0: John is 4 years old
2: Frank is 15 years old

Python supports an “else” clause for loops. Consider this common construct:

found = False
for name, age in people:
    if age > 25:
        found = True
        break
if not found:
    print "No one is older than 25."

This can be written shorter using “for-else”:

for name, age in people:
    if age > 25:
        break
else:
    print "No one is older than 25."

The “else” clause is entered when the iteration continued all the way to the end, i.e., if no “break” was executed.

The “while” loop supports an “else” clause as well.

Defining Functions

Functions are defined using the “def” keyword. Here’s a simple function taking two parameters:

def Add(a, b):
    return a + b

# Invoking it
print Add(5, 3)    # prints 8
print Add("Hello, ", "World!")    # prints “Hello, World!”
print Add([1, 2], [3, 4])    # prints [1, 2, 3, 4]

Things to note:

  • You don’t declare the data type of the parameters or of the return type
    • The function can be invoked with any two objects that support the “+” operator, similar to how template functions work in C++.
  • The indentation alone determines where the function ends

Note: C++ programmers might wonder whether the lack of explicit data type declarations results in more bugs. My experience is that it’s very rare for a bug in a Python program to be caused by a data type mismatch. It is still a good idea to have a unit-testing suite with high code coverage for your Python code. This way, you can often detect such problems faster than the C++ compiler could parse the header files. 🙂

Default parameters are also possible:

def Greet(greeting, who="World"):
    print "%s, %s!" % (greeting, who)

# Invoking it
Greet("Hello")    # prints “Hello, World!”
Greet("Good morning", "Vietnam")    # prints “Good morning, Vietnam!”

You can always specify the parameter names explicitly, in any order, regardless of whether there’s a default value or not:

Greet(who="Forrest", greeting="Run")    # prints “Run, Forrest!”

Another example, with several default parameters:

def Print(a, b=1, c=2, d=3):
    print a, b, c, d
    # If there is no explicit “return”, this is equivalent to
    # return None

# Invoke it:
Print(0)    # prints 0 1 2 3
Print(0, 4, 8 )    # prints 0 4 8 3
Print(0, c=5)    # prints 0 1 5 3
Print(0, c=7, 33)    # syntax error “non-keyword arg after keyword arg”

Returning More Than One Value

It is possible to return more than one value. More precisely, you can return a tuple and assign the elements of the tuple to individual variables. There is no magic involved here. We’ve seen all of this in the section about Tuples already.

def GetPerson():
    return "John", 4

name, age = GetPerson()
print name, age
person = GetPerson()
print person

Parameter Passing

When you pass parameters to a function, a reference to the passed object is added to the local scope of the function.

  • When you modify the object in-place, the caller sees the changes, because the local parameter name is a reference to the same object that the caller sees.
  • When you assign a new value to the local parameter name, the object doesn’t change. The parameter name is now a reference to a different object, but this does not affect the contents of the original object.
def Func(a, b, c):
    a += "!!!"
    b.append(5)
    c = []

txt = "???"
list1 = [1, 2, 3]
list2 = [1.0, 2.0]
Func(txt, list1, list2)
print "txt =", txt
print "list1 =", list1
print "list2 =", list2

Output:

txt = “???”
list1 = [1, 2, 3, 5]
list2 = [1.0, 2.0]

This is what happens:

  • When the function is invoked, it creates three local names that contain references to the passed objects: a = txt, b = list1, c = list2
  • The line a += “!!!” assigns a new object reference to the local name a. It does not change the string in-place. (Strings cannot be changed in-place at all because they are immutable objects.)
  • The line b.append(5) appends a value to the object pointed to by b. This is the same object that the caller knows by the name list1.
  • The line c = [] assigns a new object reference to the local name c. It does not modify the object that c referred to earlier.

Working with Text Files

The built-in “open” function can be used to return file objects of existing or new files. The file objects contain “read” and “write” methods. For writing to a file, the “print” keyword supports the “>>” operator.

This code creates a new file:

f = open("new.txt", "w")
f.write("This is the first linen")
print >> f, "The second line"
print >> f, "n".join(["a", "b", "c", "d"])
f.close()

The new file contains these lines:

This is the first line
The second line
a
b
c
d

There are several ways of reading a text file. You can read the entire contents at once as a string:

>>> open("new.txt").read()
… 'This is the first linenThe second linenanbncndn'

You can read the entire contents at once as a list of lines:

>>> open("new.txt").readlines()
… ['This is the first linen', 'The second linen', 'an', 'bn', 'cn', 'dn']

You can iterate over the file object, which reads the lines one by one:

>>> for ln in open("new.txt"):
>>>     print ln.rstrip("n")    # strip the newline at the end of each line
… This is the first line
… The second line
… a
… b
… c
… d

You can call the “readline” method repeatedly until it returns an empty string:

>>> f = open("new.txt")
>>> while True:
>>>     ln = f.readline()
>>>     if not ln:
>>>         break
>>>     print ln.rstrip("n")    # strip the newline at the end of each line
… This is the first line
… The second line
… a
… b
… c
… d

Using the Standard Library

Python comes with a comprehensive library of modules for various tasks. See the Global Module Index in the Python Manuals for a list of available modules.

This is a list of some of the most commonly used modules and their purpose:

  • os: Operating system interfaces for working with files and directories, accessing environment variables, invoking external programs, etc.
  • sys: Command-line arguments, file objects for STDOUT and STDERR, internal interpreter variables, etc.
  • pprint: Pretty-print Python objects such as lists and dicts
  • StringIO: Provides the StringIO class, which behaves like an in-memory file. Similar to std::stringstream in C++.
  • unittest: Unit-testing framework
  • Many others…

To use any of these modules, use the “import” keyword. Once imported, you can use the classes and functions defined in the module:

>>> import os
>>> help(os)
… help text stripped
>>> os.listdir("c:\temp")
… ['many', 'files', 'in', 'here']
>>> from os import listdir
>>> listdir("c:\temp")

We’ll take a closer look at the standard library in the next lessons.

Advertisement

Leave a Reply

Your email address will not be published. Required fields are marked *