
Refreshing my Python, I looked up some common pitfalls.
More links at the end
definition
Immutable objects are numbers and strings, while mutable objects include lists and tuples.
class attributes are shared for mutable objects
to wit:
>>> class Foo:
... i = 0
... l = []
...
>>> f = Foo()
>>> g = Foo()
>>> f.i = 100
>>> g.l.append(100)
>>> f.i, g.i
(100, 0)
>>> f.l, g.l
([100], [100])
appending the mutable class attribute affects all instances. it’s best to initialize our objects to new instances, like so:
>>> class Foo:
... l = []
... def __init__(self):
... self.l = [] # set l to a new object
...
>>> f = Foo()
>>> g = Foo()
>>> f.l.append(123)
>>> g.l.append(456)
>>> f.l, g.l
([123], [456])
mutable default arguments
consider:
>>> def bar(x=[]):
... x.append(4)
... print x
...
>>> bar()
[4]
>>> bar()
[4, 4]
>>> bar()
[4, 4, 4]
that was unexpected, but makes this very clear: mutable default arguments are bound once, when the function is created, not when it is called.
this behaviour will change any lists you pass to that same argument:
>>> x = [1, 2, 3]
>>> bar(x)
[1, 2, 3, 4]
>>> x # our object was modified
[1, 2, 3, 4]
this can be useful if kept in mind, where multiple objects need modifications returned by a function.
float point rounding errors
Because of the way machines store floating digits, consider this:
>>> 0.1
0.10000000000000001
>>> str(0.1)
'0.1'
>>> repr(0.1)
'0.10000000000000001'

Question: What best approach do we take when performing comparisons on floats?
Answer: Use Decimal where strict equality invariants is needed.
>>> from decimal import *
>>> 0.1
0.10000000000000001
>>> Decimal('0.1')
Decimal('0.1')
More on Decimals at the Python docs page
Multiple Exception Handling
>>> try:
... 1/0
... except ZeroDivisionError, e:
... print e
Will place the exception instance in e (the optional name of our exception object). Place multiple handlers in a tuple to cover many errors:
try:
...something that raises an error...
except (IndexError, ValueError):
# does catch IndexError and ValueError
Links