Wrap Your Mind Around Python:

a Tutorial

George Belotsky

Open Light Software Inc.

questions@openlight.com

Seneca FSOSS 2006

What is Python?

Who Uses Python?

A Brief Language Taxonomy

Language Taxonomy

What We'll Be Covering

Questions are welcome! There is no such thing as a stupid question!

An Interactive Python Session

Python Session Screenshot

Python Fundamentals

Data Types and Structures: Numbers

From "Python Tutorial" by Guido van Rossum, section 3.1.1

Data Types and Structures: Strings

From "Python Tutorial" by Guido van Rossum, section 3.1.2

Data Types and Structures: Lists

From "Python Tutorial" by Guido van Rossum, section 3.1.4

Data Types and Structures: Dictionaries

From "Python Tutorial" by Guido van Rossum, section 5.5

Notes on Data Types and Structures

Type System

Python is strongly but dynamically typed.

>>> var = 5
>>> 5/2
2
>>> 5 + 'test'
Traceback (most recent call last):
  ...
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> var = 'string'
>>> var + 'test'
'stringtest'
>>> var/2
Traceback (most recent call last):
  ...
TypeError: unsupported operand type(s) for /: 'str' and 'int'

Control Flow: "If" Statement

From "Python Tutorial" by Guido van Rossum, section 4.1

Control Flow: "While" Loop

From "Python Tutorial" by Guido van Rossum, section 3.2

Control Flow: "For" Loop and "range()"

From "Python Tutorial" by Guido van Rossum, section 4.2 and section 4.3

Error Handling

Dealing with Exceptions

Pattern 1.

 
>>> try:
...   raise Exception, 'Error'
... except Exception, e:
...     print e
...     raise
... else: 
...     print 'No Error'            
... 
Error
Traceback (most recent call last):
  ...
Exception: Error

Dealing with Exceptions, Cont.

Pattern 2.

 
>>> try:
...     raise Exception, 'Error'
... finally:
...     print 'Cleaning Up'
... 
Cleaning Up
Traceback (most recent call last):
  ...
Exception: Error

In Python 2.5, you can also add the finally clause to Pattern 1.

The "with" Block

Python's Object Model

Objects

First, let's try building objects by hand. This is what you would do with a language such as C -- which has no explicit Object-Oriented features.

class Something(object): pass  #Ignore this for now!
pen = Something()

pen.is_open = True     #Add an attribute

print pen.is_open

Objects, Cont.

Objects also have behavior, not just attributes.

def write(self, data):
    if not self.is_open:
        raise Exception, 'Open the pen before writing'
    print data

write(pen, 'Hello')
pen.is_open = False
write(pen, 'Hello')

Attaching Behaviors to Objects, Dynamically

This illustrates Python's ability to build arbitrary objects at run time.

import types
pen.write = types.MethodType(write, pen)
pen.write('Hello')

Duck Typing

Is this a pen ... or a duck?

def say(self):
    if self.is_lame:
        return 'Help!'
    else:
        return 'Quack!'

pen.is_lame = False
pen.say = types.MethodType(say, pen)
print pen.say()

Python is strongly but dynamically typed. This allows a very direct approach to polymorphism.

Polymorphism

Polymorphism is the most important aspect of Object-Oriented Development

def make_speak(speaker):   #Note: just a plain function, not a method
    print speaker.say()    #The "speaker" can be anything -- as long as it has 
                           #  a "say" interface

make_speak(pen)

Classes

Constructing objects directly is great for special cases, but is too tedious for everyday programming tasks. What if you need several "pen" objects, for example? We need a meta-object to describe pens. Such a meta-object is called a Class.

class Pen(object):
    def __init__(self):
        self.is_open = True
    
    def write(self, data):
        if not self.is_open:
            raise Exception, 'Open the pen before writing'
        print data

another_pen = Pen()
another_pen.write('Hello, Again')

Attaching Methods to Classes, Dynamically

Just like Python allows you to effectively modify an object's type at run time, you can similarly change a class at run time.

Pen.say = say
another_pen.is_lame = False
print another_pen.say()

Of course, you can also generate entire classes at run time.

Duck = type('Duck', (), {'is_lame':False, 'say':say})
duck = Duck()
print duck.say()

Inheritance

Goose is a Duck.

class Goose(Duck):
    def say(self):
        return Duck.say(self)+' Honk!'

goose = Goose()
print goose.say()

Prefer Delegation (Composition) to Inheritance!

GooseDelegator has a Duck (or something else, as long as the interface is correct).

class GooseDelegator(object):
    def __init__(self, delegate):
        self._delegate = delegate

    def say(self):
        return self._delegate.say()+' Honk!'

dgoose = GooseDelegator(Duck())
print dgoose.say()

Metaclasses

A Cross-Cut Example: Logging

class MetaClassLogger(type):
    def __init__(mcls, name, bases, attrs):
        def logger(self, msg):
            print msg
        mcls.log = logger


class Loggable(object):
    __metaclass__ = MetaClassLogger

    def method_one(self, data):
        self.log(data)

    def method_two(self):
        self.log('Operation Succeeded.')


loggable = Loggable()
loggable.method_one('Test')
loggable.method_two()

Structuring Larger Programs

When writing larger programs, break the code up into modules and packages.

Program Structure

Modules

import time 
import time as T
from time import localtime
from time import *

Packages

Example Applications

3D Simulation with VPython

The VPython example program.

Simple Web Client

Example 1 from "Understanding Network I/O: From Spectator to Participant".
import urllib  
import re      

url = 'http://weather.noaa.gov/weather/current/KNYC.html'
webpage = urllib.urlopen(url).read()

match = re.search(r'(-?\d+(?:\.\d+)?) F',webpage,re.S)

print 'In New York, it is now',match.group(1),'degrees.'

Web Client with a GUI

Example 6 from "Understanding Network I/O: From Spectator to Participant".

the GUI-based simple client

Python 2.5: WSGI -- "Python Servlets"

Web Application Using mod_python

from mod_python import apache

def handler(req):
    req.content_type = 'text/plain'
    req.write('Hello, World')
    return apache.OK

Processing the Path

Make sure you validate all user input -- such as req.filename below -- because it may contain data designed to break your system!

from mod_python import apache

def handler(req):
    req.content_type = 'text/plain'
    req.write('You requested: '+req.filename)
    return apache.OK

Adding Session Management

from mod_python import apache
from mod_python import Session

def handler(req):
    req.content_type = 'text/plain'

    session = Session.Session(req)
    if session.is_new():
        session['addr'] = req.connection.remote_ip
        session.save()
        req.write('Hello, World')
    else:
        req.write('Hello Again!')
    
    return apache.OK

Handling User Input

from mod_python import apache
from mod_python import util

def handler(req):
    req.content_type = 'text/plain'

    fields = util.FieldStorage(req)
    name = fields.getfirst('name', '').strip()  

    if name:
       if (not name.isalnum()) or (len(name) > 50):
          raise Exception, 'Malformed Name'
       req.content_type = 'text/plain'       
       req.write('Hello, '+name)
    
    return apache.OK

Further Reading