Archive for March, 2011
Sometimes we’d like to have a class that is tolerant of attribute accesses that weren’t anticipated at class design time, returning a default ‘None’ value for an uninitialized attribute. Using defaultdict to override the `__dict__` attribute makes this very easy:
from collections import defaultdict class X(object): def __init__(self): self.__dict__ = defaultdict(lambda : None) def __getattr__(self, attr): return self.__dict__[attr]
Now we can initialize an object with some attributes, but access others and get back the default None:
x = X() x.color = "RED" x.size = 6 print x.color print x.size print x.material
RED 6 None
Of course, this defeats a key validation feature in Python, so you’ll need to take extra care that you specify attributes correctly.
From time to time, I find that I need a function to return +1, 0, or -1 representing the sign of a value: +1 or -1 for positive or negative values, or 0 for a zero value. I remember learning this as the sgn function in high school. Python’s standard lib leaves this out, but does supply cmp as a built-in, so the standard approach would probably be to define sgn using:
sgn = lambda x : cmp(x,0)
I found a nice website of Bit-Twiddling Hacks the other day, and it had a nice alternative for sgn, which in Python would be:
sgn = lambda x : (x>0) - (x<0)
The elegance of this appeals to me and I did a quick timing pass:
C:\Users\Paul>python -m timeit "[cmp(x,0) for x in (-100,0,14)]"
1000000 loops, best of 3: 0.645 usec per loop
C:\Users\Paul>python -m timeit "[lambda x:x>0 - x<0 for x in (-100,0,14)]"
1000000 loops, best of 3: 0.496 usec per loop
So by cutting out the repeated function calls to cmp, this also has the benefit of being just a tad faster.
I came across some code today that used a set to keep track of previously seen values while iterating over a sequence, keeping just the not-seen-before items. A brute force kind of thing:
seen = set() unique =  for item in sequence: if not item in seen: unique.append(item) seen.add(item)
I remembered that I had come up with a simple form of this a while ago, using a list comprehension to do this in a single expression. I dug up the code, and wrapped it up in a nice little method. This version accepts any sequence or generator, and makes an effort to return a value of the same type as the input sequence:
def unique(seq): """Function to keep only the unique values supplied in a given sequence, preserving original order.""" # determine what type of return sequence to construct if isinstance(seq, (list,tuple)): returnType = type(seq) elif isinstance(seq, basestring): returnType = type(seq)('').join else: # - generators and their ilk should just return a list returnType = list try: seen = set() return returnType(item for item in seq if not (item in seen or seen.add(item))) except TypeError: # sequence items are not of a hashable type, can't use a set for uniqueness seen =  return returnType(item for item in seq if not (item in seen or seen.append(item)))
My first pass at this tried to compare the benefit of using a list vs. a set for seen – it turns out, both versions are useful, in case the items in the incoming sequence aren’t hashable, in which case the only option for seen is a list.