Extra AttributeError inside property - possible bug ?

Peter Otten __peter__ at web.de
Tue Sep 1 03:08:56 EDT 2015


dunric29a at gmail.com wrote:

> Hello,
> 
> bellow is a simple Python2 example of a class which defines __getattr__
> method and a property, where AttributeError exception is raised:
> 
> from __future__ import print_function
> 
> class MyClass(object):
>     def __getattr__(self, name):
>         print('__getattr__ <<', name)
>         raise AttributeError(name)
>         return 'need know the question'
> 
>     @property
>     def myproperty(self):
>         print(self.missing_attribute)
>         return 42
> 
> my_inst = MyClass()
> print(my_inst.myproperty)
> 
> # produces following output
> __getattr__ << missing_attribute
> __getattr__ << myproperty
> Traceback (most recent call last):
>   File "a.py", line 84, in <module>
>     main()
>   File "a.py", line 74, in main
>     print('==', my_inst.myproperty)
>   File "a.py", line 36, in __getattr__
>     raise AttributeError(name)
> AttributeError: myproperty
> 
> 
> By the documentation
> https://docs.python.org/2/reference/datamodel.html#object.__getattr__ , if
> class defines __getattr__ method, it gets called at AttributeError
> exception and should return a computed value for name, or raise (new)
> AttributeError exception.
> 
> Why is __getattr__ called 2nd time, with 'myproperty' argument ?!?
> self.myproperty does exist and also at first call of __getattr__ new
> AttributeException with 'missing_attribute' is raised. I can't see any
> reason for this behavior.

I believe this is an implementation accident, the code is not keeping track 
of the exact origin of the AttributeError. Until recently generators showed 
analogous behaviour and swallowed StopIterations:

$ cat stopiteration.py
from __future__ import generator_stop

def stop():
    raise StopIteration


def f(items):
    for item in items:
        yield item
        stop()


for item in f("abc"):
    print(item)
$ python3.5 -x stopiteration.py # abusing -x to skip the __future__ import
a
$ python3.5 stopiteration.py
a
Traceback (most recent call last):
  File "stopiteration.py", line 10, in f
    stop()
  File "stopiteration.py", line 4, in stop
    raise StopIteration
StopIteration

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "stopiteration.py", line 13, in <module>
    for item in f("abc"):
RuntimeError: generator raised StopIteration

If the AttributeError behaviour were to be changed a similar transition 
period would be required, so no Python prior to 3.6 would be affected.




More information about the Python-list mailing list