I'm confused about how the proposal would work. How would you prevent self.x.t from also raising AttributeMissError (thereby defeating its purpose)?

On Fri, Nov 27, 2015 at 12:18 PM, 王珺 <wjun77@gmail.com> wrote:
I think the real world use case, as property is so common, is just when __getattr__ needed. So anyone using __getattr__ in practice? In fact I'm new tweaking these advanced features of python. Any suggestions are welcome and appreciated.


In my case, I delegate failed attribute lookups to one member of the instance, as the given simple example in issue25634. For example, there's a class Point,

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

and class Circle

class Circle():
    def __init__(self, center, radius):
        self.center = center
        self.radius = radius

I don't think Circle should inherit Point. But I want to write Circle().x instead of Circle().center.x, so I write something like
    def __getattr__(self, name):
        try:
            return getattr(self.center, name)
        except AttributeError:
            raise AttributeError("'{}' object has no attribute '{}'".format(self.__class__.__name__, name)) from None


Another case is when I try to implement the design pattern of state. That is, when calling window.rightClick(), the behavior differs according to the state of the window, or window.__state. So

class ActiveState(State):
    @staticmethod
    def rightClick(self):
        print('right clicked')
class InactiveState(State):
    @staticmethod
    def rightClick(self):
        pass

and

class Window():
    def __init__(self):
        self.__state = ActiveState
    def __getattr__(self, name):
        try:
            return partial(getattr(self.__state, name), self)
        except AttributeError:
            raise AttributeError("'{}' object has no attribute '{}'".format(self.__class__.__name__, name)) from None

(The real situation is more complicated. In fact I've written a state module, and I think I can publish it in a week if anyone is interested.)


> Is that really an imperfection? It says right there in the docs for __getattribute__ that you can delegate to __getattr__ by raising AttributeError
Just like raising StopIteration in generator, as described in PEP479. Although I'm not sure StopIteration has ever been documented as one way to exit generator. And I admit that an unintentional AttributeError in __getattribute__ is a rare case if ever.

2015-11-28 2:34 GMT+08:00 Andrew Barnert <abarnert@yahoo.com>:
It seems like you can get some of the benefits of this proposal without backward compat issues.

Instead of changing things so AttributeError from __getattribute__ or a descriptor no longer calls __getattr__, just add a new subclass that doesn't, and change the Descriptor HOWTO to suggest using that subclass (with a bit of discussion that says you can use AttributeError if you want to trigger __getattr__, but usually you won't).

That wouldn't fix any current code, but it also wouldn't break any code that intentionally uses the features as documented. And it would make it easy to write correct new code.

One more thing:
Without descriptor, unexpected AttributeError could only come from overriding __getattribute__, which is a rare case, although still an imperfection.
Is that really an imperfection? It says right there in the docs for __getattribute__ that you can delegate to __getattr__ by raising AttributeError, so if someone does that, presumably it's intentional. It's not like the case with descriptors, where you have to think through the interaction of multiple features to figure out that raising an AttributeError will call __getattr__, and therefore many such uses are probably bugs.

Sent from my iPhone

On Nov 27, 2015, at 09:49, 王珺 <wjun77@gmail.com> wrote:

Hello everyone:

I'm suggesting a modification to the AttributeError/__getattr__ mechanism, see issue25634:
http://bugs.python.org/issue25634

I used __getattr__ sometimes, and descriptor especially property is so widely used. I wonder whether someone had encountered the same problem with me.

However, this is a complicated problem including performance issues, and backward compatibility.

Thanks for your attention,
Jun Wang
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/



--
--Guido van Rossum (python.org/~guido)