Brian Cole wrote: > I've been programming in Python for about 6 years now. One of the > features I adore the most is the very useful error messages and stack > traces that make it easy to debug. However, today I ran into a > difficult to trace bug because the stack trace was reporting the > problem in the wrong place. > > class Delegator(object): > def __init__(self, obj): > self.obj = obj > def __getattr__(self, attr): > return getattr(self.obj, attr) > > class SpecializedDelegator(Delegator): > def get_blah(self): > return ["Returning Blah"].upper() > blah = property(fget=get_blah) > > print SpecializedDelegator("Doesn't Matter").blah > > The stack trace is: > Traceback (most recent call last): > File "test.py", line 12, in ? > print SpecializedDelegator("Doesn't Matter").blah > File "test.py", line 5, in __getattr__ > return getattr(self.obj, attr) > AttributeError: 'str' object has no attribute 'blah' > > Which is correct, but says nothing about the real problem inside the > get_blah method. Is there a good reason that when a property's fget > function throws an AttributeError that it should fall back on > __getattr__? I would think since the attribute was explicitly defined > as a property the property function should be allowed to fully crash > and burn. > > Note: This example is broken up into two classes because that is how I > discovered it. Since both classes were in separate files it added to > the agony of debugging this. Luckily I was making a small incremental > change so I could just back up and figure out what went wrong. > > Thanks, > Brian
Your __getattr__ in in Delegator is circumventing the property in SpecializedDelegator: py> class Delegator(object): ... def __init__(self, obj): ... self.obj = obj ... def __getattr__(self, attr): ... return getattr(self.obj, attr) ... py> class SpecializedDelegator(Delegator): ... def get_blah(self): ... return ["Returning Blah"].upper() ... blah = property(fget=get_blah) ... py> print SpecializedDelegator("Doesn't Matter").blah ------------------------------------------------------------ Traceback (most recent call last): File "<ipython console>", line 1, in <module> File "<ipython console>", line 5, in __getattr__ <type 'exceptions.AttributeError'>: 'str' object has no attribute 'blah' py> class Delegator(object): ... def __init__(self, obj): ... self.obj = obj ... def __getattr__(self, attr): ... if hasattr(self.obj, attr): ... return getattr(self.obj, attr) ... else: ... return self.__getattribute__(attr) ... py> class SpecializedDelegator(Delegator): ... def get_blah(self): ... return ["Returning Blah"].upper() ... blah = property(fget=get_blah) ... py> print SpecializedDelegator("Doesn't Matter").blah ------------------------------------------------------------ Traceback (most recent call last): File "<ipython console>", line 1, in <module> File "<ipython console>", line 8, in __getattr__ File "<ipython console>", line 3, in get_blah <type 'exceptions.AttributeError'>: 'list' object has no attribute 'upper' James -- James Stroud UCLA-DOE Institute for Genomics and Proteomics Box 951570 Los Angeles, CA 90095 http://www.jamesstroud.com/ -- http://mail.python.org/mailman/listinfo/python-list