Question

I am trying to implement a class in which an attempt to access any attributes that do not exist in the current class or any of its ancestors will attempt to access those attributes from a member. Below is a trivial version of what I am trying to do.

class Foo:
    def __init__(self, value):
        self._value = value

    def __getattr__(self, name):
        return getattr(self._value, name)

if __name__ == '__main__':
    print(Foo(5) > Foo(4)) # should do 5 > 4 (or (5).__gt__(4))

However, this raises a TypeError. Even using the operator module's attrgetter class does the same thing. I was taking a look at the documentation regarding customizing attribute access, but I didn't find it an easy read. How can I get around this?

Was it helpful?

Solution

If I understand you correctly, what you are doing is correct, but it still won't work for what you're trying to use it for. The reason is that implicit magic-method lookup does not use __getattr__ (or __getattribute__ or any other such thing). The methods have to actually explicitly be there with their magic names. Your approach will work for normal attributes, but not magic methods. (Note that if you do Foo(5).__lt__(4) explicitly, it will work; it's only the implicit "magic" lookup --- e.g., calling __lt__ when < is used) --- that is blocked.)

This post describes an approach for autogenerating magic methods using a metaclass. If you only need certain methods, you can just define them on the class manually.

OTHER TIPS

__*__ methods will not work unless they actually exist - so neither __getattr__ nor __getattribute__ will allow you to proxy those calls. You must create every single methods manually.

Yes, this does involve quite a bit of copy&paste. And yes, it's perfectly fine in this case.

You might be able to use the werkzeug LocalProxy class as a base or instead of your own class; your code would look like this when using LocalProxy:

print(LocalProxy(lambda: 5) > LocalProxy(lambda: 4))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top