Gotcha I never ran into before

James Stroud jstroud at mbi.ucla.edu
Thu Aug 9 20:45:38 EDT 2007


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/



More information about the Python-list mailing list