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 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 '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 (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 first object that is true, 
plan = a or b                   # it can be written as a terse idiom instead of if/else. 
if a:                           # 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]                         # first elem 
data[-1]                        # 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 first two 
data[-2:]                       # last two elems 
data[:-2]                       # all elems excluding last two 
data[::-1]                      # reverses order (Python 2.3)

del list[i]                     # delete 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 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 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 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 type of an object 
if isinstance(i,int):
>>> type(i)
<type 'int'>

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

pitfalls, traps, 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 
# first-level elements. 
# If a list contains nested lists, 
# a deep copy is necessary to make copies 
# of 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 elements themselves. 
obj1 = MyClass()
obj2 = MyClass()
list = [ obj1, obj2 ]
del list[:]       # list emptied but obj1, obj2 survive 

# Pitfall: To avoid slice pitfalls: 
# Remember that lower bound is inclusive but upper is exclusive. 
# Think of indices as pointing between characters, 
# with left edge of first character numbered 0. 
# 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 last 
del list[:]       # right 

# Pitfall: invoking base constructors. 
# Python doesn't call __init__() methods of base (ancestor) classes. 
# 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, 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 name of class. 
# Assigning a class attribute using name of an instance is a pitfall 
# as it will create a per-instance variable that'll override 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 obvious __delattr__ 

code snippets

# Dynamically create a list of lists (multi-dimensional list). 
# This snippet is from pyspaceinvaders: 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 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) )))

commentary/opinion

positive:
Python code is very sleek and readable because of indentation. Python offers a large set of libraries.

negative:
A few design mistakes were made in syntax of Python, rather than live with those mistakes, syntax was improved and redefined, but compatibility was broken. Python can be embedded in a C++ program, but will bring lots of baggage. If only scripting capability is needed, Lua should be more suitable.