Experiment: Replace __setattr__ With A Descriptor
    
  
As part of daily life I see a ton of Python code. Between the code at work and all of the open source projects I watch I'm surprised my eyes don't bleed. Over the years my style has changed dramatically. I guess you could say I am getting more Pythonic. Looking back at old code sometimes just make me feel ill. I know better now.
There was a project that I worked on where we wanted to ensure all attributes were typed properly. (No comments about this - it's not the point of the post) To do this we used an evil combination of Hungarian notation and __setattr__ magic. An example class looks something like this:
  
class Data(object):
    def __init__(self, strX='', fltY=0.0, intZ=0):
        self.strX = strX
        self.fltY = fltY
        self.intZ = intZ
    def __setattr__(self, name, value):
        if name.startswith('int'):
            object.__setattr__(self, name, int(value))
        elif name.startswith('flt'):
            object.__setattr__(self, name, float(value))
        elif name.startswith('str'):
            object.__setattr__(self, name, str(value))
        else:
            object.__setattr__(self, name, value)
As ugly as it is it actually works. All attributes are forced to a type based off of their name. I know the __setattr__ is rather slow, but I never really gave it a second thought even thought I periodically see this code. This weekend a neuron misfired and I had an idea. So I gave this a whirl:
class TypedAttr(object):
    def __init__(self, _type, value):
        self._type = _type
        self._default = self._value = value
    def __get__(self, obj, _type):
        return self._value
    def __set__(self, obj, value):
        self._value = self._type(value)
    def __delete__(self, obj):
        self._value = self._default
class Data(object):
    strX = TypedAttr(str, '')
    fltY = TypedAttr(float, 0.0)
    intZ = TypedAttr(int, 0)
This Data class is must cleaner. The TypedAttr can be defined in another module making this code much smaller and more declarative.
The descriptor approach out performs the __getattr__. My tests were using the timeit module in Python 2.5. Running the old way gave me about 25 usec and the new way was 11 usec.
I think I'll suggest the change :-)
   Subscribe in a reader
 Subscribe in a reader
   
    