dunric...@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. -- https://mail.python.org/mailman/listinfo/python-list