Python Programming Language

Index

Python Space Invaders

If you notice any mistakes or have additions, click here.

Basic Syntax


stmt:                           # trailing colon introduces 
    stmt2                       # an indented statement or clause 

#                               # comment 

\                               # line continuation 

;                               # statement separator (like C) 
if cash > price: Eggs(); Spam() # we eat both if we've enuff money 

True False                      # note spelling (Python 2.3) 

"abc"                           # strings can be enclosed 
'abc'                           # in single or double quotes 

s = 'abc'
s[0] = 'A'                      # wrong: strings are immutable 

(n,n,...)                       # tuple 
n,n,...                         # tuple 
t = (1, 2, 3)                   # named tuple variable 
n = t[0]                        # access tuple element 

t = ('math',101)                # create named tuple 
(course,num) = t                # unpack tuple 

[n,n,...]                       # list 
list = [ 'a', 'b', 'c' ]        # list variable 
list[1]                         # access element 

list = [ 'eggs', 12 ]           # heterogenous lists are supported by Python 
                                # but using tuples as elements may be better 

d = {'vorlon':0, 'shadow':1}    # create dictionary 
d['vorlon']                     # access by key 

None                            # NULL 

not                             # logical/boolean not returns True/False 

# Logical/boolean and/or 
# For 'X or Y', returns X if it's true, else Y 
# For 'X and Y', returns X if it's false, else Y 
# Both return an object, not true/false nor 0/1! 
a = 0; b = 2; plan = a or b     # plan = 2 (not 1 as one might expect)
i = 0; L = []; z = i or L       # z = [] (z = L) 
i = 0; L = []; z = L or i       # z = 0  (z = i) 

& | ~                           # bitwise 

== != < > <= >=                 # equality, relational 

is                              # object identity 
is not

**                              # power (x^y) 

//                              # floor division (truncates to integer) 

pass                            # NOP 

*                               # multiple meanings: 
str = 2 * 'abc'                 # repeats a string: 'abcabc' 
x = (1, 2, 3)                   # unpacks a tuple into individual values 
func( *x )                      # pass 3 separate args rather than a tuple 

+= -= *= etc                    # shorthand like C 

if <cond>:                      # conditional 
[elif <cond>:]
[else:]

while <cond>:                   # while loop 
    [break]                     # break out of looping 
    [continue]                  # iterate to top of loop 
[else:]                         # 'else' clause will execute when condition becomes false. 
                                # To be exact, 'else' will execute unless 'break' was executed. 

for item in sequence:
    if item == sought:
        break
else:                           # This is the Pythonic way of saying "if item not found". 
    print item, 'not found'     # 'else' clause will execute unless 'break' was executed. 

return                          # implicitly returns None 
return (res1,res2)              # a tuple can be used to return multiple values 

try:                            # except clause executed if exception matches 
[except [exception[,value]]]:   # omitted name matches any exception 
else:                           # else clause executed if no exception 

def func( arg1, arg2 = 10 )     # second arg has a default 
def func( *arg )                # arg is a tuple (arbitrary number of arguments) 
func( (123, 456, 789) )         # arg = ( 123, 456, 789 ) 
foo( name='eggs', age='12' )    # args can be specified by name 
def func( arg1, **arg2 )        # final arg is a dictionary 

float(123) float('123.0')       # convert integer/string to float 
str(123)                        # convert to string (stringify) 
`123`                           # convert to string (stringify) (deprecated) 
int(1.5)                        # convert to integer (truncate) 
bool(x)                         # convert to boolean 
hex(15)                         # convert to string in hex format 
int('101',2)                    # convert to int from binary number in string 

# A list comprehension is a shorthand with two usual forms: 
# [ x for x in seq ] 
# [ x for x in seq if expr ] 
# A list comprehension creates a new list by appending 'x' 
# on every iteration of 'for x in seq'. 
# If an optional 'if' clause is written, 'x' is only appended 
# if the 'if' clause evaluates to true. 
list = [ 1, 2, 3, 4, 5, 6 ]
result = [ 2*x for x in list]              # new list whose elements are double 
result = [ x for x in list if x % 2 == 0 ] # new list with even values 

# lamba creates an anonymous function.  Unlike 'def', 
# formal args aren't parenthesized.  A lambda is limited to 
# being an expression and its result is implicitly returned. 
sum = lambda a, b: a + b
x = sum(10,20)

# Class attributes have similarities to C++ static members. 
# Inside a class block, they're set using their unqualified names. 
# But inside a method, class attributes require class-qualified names 
# to distinguish them from method local vars and instance attributes. 
class Class:
    msCnt = 0         # right 
    Class.msCnt = 0   # wrong (the class name isn't valid yet) 

    def __init__( self ):
        print msCnt        # wrong (non-existent local var) 
        print s.msCnt      # technically wrong (will work): class attribute confused as instance attribute 
        print Class.msCnt  # right 
        self.msCnt += 1    # wrong: changes this instance's attribute, not class attribute 
        Class.msCnt += 1   # right 

Common Phrases, Expressions, & Idioms


person = 'Methuselah'           # counterpart to C printf() 
age = 969
print '%s lived %d years.' % (person, age)

if 90 <= percent <= 100:        # between test 

x or y                          # result is x if x is True or y 
x and y                         # result is y if x is True or x 
return x or y or None           # return x if it's True, or y if it's True, or None 

a, b = b, a                     # swap 
a, b = 0, 2                     # Since boolean 'or' returns the first object that is true, 
plan = a or b                   # it can be written as a terse idiom instead of if/else. 
if a:                           # The result is plan = 2 (not plan = 1) 
    plan = a
else:
    plan = b

t = ()                          # empty tuple 
t = 'a',                        # trailing comma necessary to assign tuple 

t = ('abc',1)                   # to modify a tuple: 
t[1] = 2                        # wrong 
t = (t[0],2)                    # right (by reassignment) 

tup = (64, 'bits')              # comparing objects of utterly different types is allowed 
if tup[0] == tup[1]:            # which may be useful with heterogenous sequences 

list = []                       # to append to a list: 
list[0] = 'a'                   # wrong, would throw IndexError 
list.append( 'a' )              # right 

list = [None] * 256             # pre-allocate 256 elements (None repeated 256 times) 
list[255] = 1                   # ok 

list[:]                         # select entire sequence 
str[:]                          # don't write list[0:-1] (see Pitfalls) 

for i in xrange(10): print i    # iterate thru {0,..,9} 
                                # avoid range() which has a pitfall 

for element in [1, 3, 7, 12]:   # iterate thru a LIST 
for element in (1, 3, 7, 12):   # iterate thru a TUPLE 

for line in open('myfile.txt'): # print lines of a file 
    print line

x in seq, x not in seq          # True/False if x is/not in sequence 

word = 'abc' + 'def'            # catenate strings 

# Positive indexes are zero-based. 
# Negative indexes are allowed. 
data[0]                         # the first elem 
data[-1]                        # the last elem 

# Slicing applies to a sequence (strings, lists). 
# Lower bound is inclusive, upper bound is exclusive. 
data[:2]                        # first two elems 
data[2:]                        # all elems following the first two 
data[-2:]                       # the last two elems 
data[:-2]                       # all elems excluding the last two 
data[::-1]                      # reverses order (Python 2.3)

del list[i]                     # delete the ith element 

aString = 'abc'                 # to unpack: 
aList   = [1, 2, 3]             
aTuple  = 'Jane', 28, 'CS'      
first, second, third = aString  # unpack string 
first, second, third = aList    # unpack list 
first, second, third = aTuple   # unpack tuple 

class Object:                   # declaring a class 
    def foo( self ):            # self is always the first arg of class methods 

obj.data                        # accessing a class member 

class Derived(Object)           # deriving a class 
class Derived2(Base1,Base2)     # multiple inheritance 

class Object:                   # __init__() is always the name 
        def __init__(self):     # of every constructor in Python 

obj = Object()                  # instantiating an object from a class 

class Object:                   # Class members can be created by constructor. 
    def __init__(self):         # .data is created dynamically in this case. 
        self.data = GetData()   # Note that 'self.' is necessary. 

class Base:                     # Programmer must explicitly call 
    def __init__(self):         # base constructors in Python. 
    ...
class Derived:
    def __init__(self):
        Base.__init__(self)

class Myclass:                  # Python nearest counterpart to C++'s private 
    def __init__(self):         # is to prepend two underscores to a member. 
        self.__private = 1

# iter*() returns iterators.  Pitfall: Loop must not modify the dictionary. 
for k in d.iterkeys():          # iterate thru keys in dictionary (by iterator object) 
for v in d.itervalues():        # iterate thru values in dictionary (by iterator object) 
for (k,v) in d.iteritems():     # iterate thru pairs in dictionary (by iterator object) 
# values(),keys(),items() return lists derived from dictionary. 
for k in d.keys():              # iterate thru list of keys from dictionary 
    if k == deleted:
        del d[k]                # ok: iteration is thru list rather than dictionary 
for v in d.values():            # iterate thru list of values from dictionary 
for (k,v) in d.items():         # iterate thru list of pairs from dictionary 

i = 123                         # test the type of an object 
if isinstance(i,int):
>>> type(i)
<type 'int'>

def Func():                     # This isn't a dangling reference. 
    x = 123                     # The name 'x' is destroyed when the function returns 
    return x                    # but the object referenced by 'x' is returned. 
y = Func()

Pitfalls, Traps, and Quirks


# Pitfall: A silent NOP!  ++ is two unary positive operators in Python! 
++x

# Pitfall: Use xrange() instead of range(). 
# Same syntax.  xrange() creates an iterator.  range() creates a list. 
for i in range(10*1024*1024): #  wrong: that's why you ran out of swap-space 

# Pitfall: Trying to modify a function arg by assignment 
# is wrong because a function arg is a local name. 
Mangle(list)         # wrong: this won't be an in-place modification 
def Mangle(list):
    list = list[1:]  # wrong: creates a new list and assigns to a local name 

list = Mangle(list)  # right 
def Mangle(list):    
    list = list[1:]
    return list

list = Mangle(list)  # better 
def Mangle(list):    
    del list[0]
    return list

# Pitfall: Modifying a sequence by a loop: 
list = [ 0, 0, 0 ]
for item in list: # wrong: changes item not list[] 
    item = 1      # item is a temporary object 
for i in xrange( len(list) ):
    list[i] = 1   # right 

# Pitfall: Tuple elements cannot be re-assigned. 
# But a tuple as a whole can be. 
t = (1, 2)
t[1] = 3        # wrong 
t = (t[0], 3)   # right 

# Pitfall: For basic types, assignment effectively creates a copy. 
# But for all other objects, assignment creates a reference!! 
# Assignment to basic type: 
x = 1
y = x
x = 2  # results: x = 2, y = 1 (as you would expect) 
# Assignment to non-basic type: 
list = [ 1, 2 ]
listSaved = list
list[0] = 3          # wrong: list[0] = listSaved[0] = 3 
listSaved = list[:]  # right (shallow copy) 

# Pitfall: shallow copy vs. deep copy. 
# A shallow copy of a list only copies 
# the first-level elements. 
# If a list contains nested lists, 
# a deep copy is necessary to make copies 
# of the nested lists. 
listSaved = list[:]              # shallow copy 
import copy
listSaved = copy.deepcopy(list)  # deep copy 

# Pitfall: deleting a list element. 
list = [ 1, 2, 3 ]
list[0] = []   # wrong, turns list[0] into empty list: [ [], 2, 3 ]  
del list[0]    # right 

# Pitfall: del removes elements from a list but 
# doesn't really delete the elements themselves. 
obj1 = Myclass()
obj2 = Myclass()
list = [ obj1, obj2 ]
del list[:]       # list emptied but obj1, obj2 survive 

# Pitfall: To avoid slice pitfalls: 
# Remember that the lower bound is inclusive but the upper is exclusive. 
# Think of the indices as pointing between characters, 
# with the left edge of the first character numbered 0. 
# The right edge of element n is at index n (upper bound). 
# 
#  +---+---+---+---+---+ 
#  | A | B | C | D | E | 
#  +---+---+---+---+---+ 
#  0   1   2   3   4   5 
# -5  -4  -3  -2  -1     
# 
# For example: 
# s = 'ABCDE' 
# s[0:4] is 'ABCD' (not 'ABCDE') 
# s[-5:-1] is 'ABCD' also (s[-1:-5] would be wrong) 

# Pitfall: Intent is to remove all elements from a list: 
del list[0:-1]    # wrong, removes all elements except the last 
del list[:]       # right 

# Pitfall: invoking base constructors. 
# Python doesn't call the __init__() methods of base (ancestor) classes. 
# The programmer must explicitly call ancestor __init__() methods 
# or call super(). 

# Pitfall: Use 'global' to assign a global variable 
# by a function (similar to PHP) to avoid UnboundLocalError. 
gx = 0
def Func(x):
    global gx
    gx = gx + x
    return
def Func2():
    gx = 1    # wrong: creates gx in local scope (need global gx) 

# Pitfall: Built-in names can be reassigned by mistake. 
open = True   # wrong 

Tricks and Recipes


Trick: Portable way to locate python interpreter 

#!/usr/bin/env python

Trick: Abbreviating self 

# Writing 'self' is only a convention: it can be written as 's' for brevity. 

class Class:
    def __init__( s ):

Trick: static local variable 

# Functions can be given attributes which can serve as static local variables. 
def func( input ):
    if input == func.lastInput:    # avoid recomputing same input 
        return func.lastResult
func.lastInput  = None
func.lastResult = None

Trick: Counterpart to C++ static class member 

# Python class attributes can be used (with care) 
# as counterparts to C++ static class members. 
# By contrast, data attributes are per-instance variables. 
# A class attribute must be assigned using the name of the class. 
# Assigning a class attribute using the name of an instance is a pitfall 
# as it will create a per-instance variable that'll override the class variable. 
class Myclass:
    shared = 1
c1 = Myclass()
c2 = Myclass()
c1.shared = 2       # wrong: affects only c1 (c2.shared is still 1)
Myclass.shared = 2  # right: affects all instances of Myclass 
                    # (except those with an overriding per-instance variable) 

Trick: Constant (read-only) variables 

# By Alex Martelli: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65207 
# Put in const.py...: 
class _const:
    class ConstError(TypeError): pass
    def __setattr__(self,name,value):
        if self.__dict__.has_key(name):
            raise self.ConstError, 'Can not rebind const(%s)' % name
        self.__dict__[name] = value
import sys
sys.modules[__name__] = _const()
# that's all -- now any client-code can 
import const
# and bind an attribute ONCE: 
const.magic = 23
# but NOT re-bind it: 
const.magic = 88      # raises const.ConstError 
# you may also want to add the obvious __delattr__ 

Code Snippets


# Dynamically create a list of lists (multi-dimensional list). 
# This snippet is from Space Invaders: it has a list of 
# alien columns in which each column is a list of alien objects. 
alienColCnt = 10
alienColumns = []
for col in range(alienColCnt):
    alienColumns.append( [] )         # add list as an element (nested list) 
    alien = Alien()                   # new Alien object 
    alienColumns[col].append( alien ) # add to 2nd-level list 

# Prune invalid objects in a list. 
# Requires: Objects in elements have a .valid member. 
#           List is flat (no nested sequences). 
# Deleting items while iterating thru a list 
# is an error in Python, so a copy is used. 
def PruneList( list ):
    tmp = list[:] # copy list (shallow copy) 
    i = -1
    for obj in tmp:
        i += 1
        if not obj.valid:
            del list[i]
            i -= 1
    return

# Prune invalid objects in a list of lists (2D list). 
# Requires: Objects in elements have a .valid member. 
#           List must not be deeper than 2 levels. 
def PruneListList( listList ):
    tmpListList = listList[:] # copy list (shallow copy) 
    i = -1
    for list2 in tmpListList: # for each 2nd-level list 
        i += 1
        j = -1
        for obj in list2:
            j += 1
            if not obj.valid:
                del listList[i][j]
                j -= 1
    return

# Iterate over a list of tuples. 
tupleList = [ ('math',101), ('chemistry',102) ]
for t in tupleList:
    print 'class %s %d' % t
for (course,num) in tupleList: # alternative 
    print 'class %s %d' % (course,num)

# ------------------------------------ 
# Printing a user-defined class/object 
# ------------------------------------ 

class Myclass:
    def __init__(self,n):
        self.val = n
    def __str__(self):
        return 'val = %d' % self.val
obj = Myclass(12)
print obj

# Remove duplicates from a list. 
def Unique( l ):
    d = {}
    for k in l:
        d[k] = 1
    return d.keys()

Emacs Python Mode

Emacs Python mode by default will write TAB chars. But that causes trouble for Python in properly identifying indentation when TAB and space chars are mixed. Adding this to your ~/.emacs will force the TAB key to write 4 spaces instead.


;; ------
;; Python
;; Write TAB as 4 spaces.
;; ------
(setq python-mode-hook
      '(lambda () (progn
                    (set-variable 'py-indent-offset 4)
                    (set-variable 'py-smart-indentation nil)
                    (set-variable 'indent-tabs-mode nil) )))

Resources

Documentation:

  • Python Documentation @ python.org
  • Tutorial @ python.org
  • 'Learning with Python'   with tarball
  • Quick Reference (Python 2.3)
  • Python Programming - Jun Wang   reference
  • 'Dive Into Python' - Mark Pilgrim
  • Python Warts

Libraries:

  • PyGame
  • wxPython   GUI/widget library
  • PyKyra   sprite library

Dependencies:

  • libsdl   core SDL lib required by PyGame
  • libsdl/projects   auxillary SDL libs (libSDL_*)

Editors, IDE, class browsers:

  • idle is the standard Python IDE included in Python distributions
  • Dr. Python
  • Eric3
  • IDLE documentation
  • SPE
  • IDE Studio

Tools:

  • PyChecker   source code checker (lint remover)
  • PyLint   another source code checker (lint remover)

Software, FTP sites:

  • The Vaults of Parnassus

Games

  • Python Space Invaders
  • Python games   pygame.org
  • Carl Codemonkey   [I play this game many times in real-life.] 
    "Carl Codemonkey is a programer working for MicroSocks industries. In his work he has to gather bytes, keep away from bugs and viruses [..] stay awake by drinking coffee [..] If Carl runs out of caffeine he will fall asleep."
  • PySol   solitaire
  • Asymptopia BlackJack   install as root
home    send email
© 2013 Jim Brooks
Last modified: Thu May 17 13:25:36 EDT 2012