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