@property decorator doesn't raise exceptions

Rafe rafesacks at gmail.com
Sat Oct 25 16:16:33 EDT 2008


On Oct 24, 9:58 am, Peter Otten <__pete... at web.de> wrote:
> Rafe wrote:
> > On Oct 24, 2:21 am, Christian Heimes <li... at cheimes.de> wrote:
> >> Rafewrote:
> >> > Hi,
>
> >> > I've encountered a problem which is making debugging less obvious than
> >> > it should be. The @property decorator doesn't always raise exceptions.
> >> > It seems like it is bound to the class but ignored when called. I can
> >> > see the attribute using dir(self.__class__) on an instance, but when
> >> > called, python enters __getattr__. If I correct the bug, the attribute
> >> > calls work as expected and do not call __getattr__.
>
> >> > I can't seem to make a simple repro. Can anyone offer any clues as to
> >> > what might cause this so I can try to prove it?
>
> >> You must subclass from "object" to get a new style class. properties
> >> don't work correctly on old style classes.
>
> >> Christian
>
> > All classes are a sub-class of object. Any other ideas?
>
> Hard to tell when you don't give any code.
>
> >>> class A(object):
>
> ...     @property
> ...     def attribute(self):
> ...             raise AttributeError
> ...     def __getattr__(self, name):
> ...             return "nobody expects the spanish inquisition"
> ...>>> A().attribute
>
> 'nobody expects the spanish inquisition'
>
> Do you mean something like this? I don't think the __getattr__() call can be
> avoided here.
>
> Peter


Peter nailed it, thanks! I thought __getattr__ was a symptom, not a
cause of the misleading exceptions. Here is a complete repro:


The expected behavior...

>>> class A(object):
... @property
... def attribute(self):
...     raise AttributeError("Correct Error.")
>>> A().attribute
Traceback (most recent call last):
  File "<console>", line 0, in <module>
  File "<console>", line 0, in attribute
AttributeError: Correct Error.


The misleading/unexpected behavior...

>>> class A(object):
... @property
... def attribute(self):
...     raise AttributeError("Correct Error.")
... def __getattr__(self, name):
...     cls_name = self.__class__.__name__
...     msg = "%s has no attribute '%s'." % (cls_name, name)
...     raise AttributeError(msg)
>>> A().attribute
Traceback (most recent call last):
  File "<console>", line 0, in <module>
  File "<console>", line 0, in __getattr__
AttributeError: A has no attribute 'attribute'.


Removing @property works as expected...

>>> class A(object):
... def attribute(self):
...     raise AttributeError("Correct Error.")
... def __getattr__(self, name):
...     cls_name = self.__class__.__name__
...     msg = "%s has no attribute '%s'." % (cls_name, name)
...     raise AttributeError(msg)
>>> A().attribute()   # Note the '()'
Traceback (most recent call last):
  File "<console>", line 0, in <module>
  File "<console>", line 0, in attribute
AttributeError: Correct Error.


The docs seem to suggest this is impossible:
"Called when an attribute lookup has not found the attribute in the
usual places (i.e. it is not an instance attribute nor is it found in
the class tree for self). name is the attribute name. This method
should return the (computed) attribute value or raise an
AttributeError exception."

Can anyone explain why this is happening? Is it a bug? I can write a
workaround to detect this by comparing the attribute name passed
__getattr__ with dir(self.__class__) = self.__dict__.keys(), but how
can I raise the expected exception?


Thanks,

- Rafe



More information about the Python-list mailing list