7

I am getting maximum recursion depth error in the line if hasattr(self, '_ubuffer'). Can anyone see what am I doing wrong here? Whole code of the function is:

def __getattr__(self, name):
        if hasattr(self, '_ubuffer'):
            buffer = object.__getattribute__(self,'_ubuffer')
            if name in buffer.dtype.names:
                return buffer.data[name]
        return object.__getattribute__(self,name)
1

3 Answers 3

6

hasattr calls __getattr__ which would cause the recursion. From the docs:

hasattr(object, name) The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.) [my emphasis]

One way to get around this problem might be to replace if hasattr(self, '_ubuffer') with something like if '_ubuffer' in self.__dict__.

Sign up to request clarification or add additional context in comments.

Comments

1

You can use the superclass implementation for regular attribute access:

def __getattr__(self, name):
    try:
        buffer = super(MyClass, self).__getattr__('_ubuffer')
    except AttributeError:
        raise AttributeError('Attribute {} not found.'.format(name))

    if name in buffer.dtype.names:
        return buffer.data[name]
    else:
        raise AttributeError('Attribute {} not found.'.format(name))

1 Comment

I like this way more. It is less intrusive (no need to dig up internal __dict__ attribute), it is more portable since it also works for classes using __slots__ instead of __dict__, and it is faster (it is recommended to sure try ... catch ... blocks instead of if ... else ... if it is never supposed to fail).
1

The method proposed by @maciej-gol is quite nice, but it does not handle the common case where the super class does not define custom __getattr__ (at least for Python3). To avoid such issue, it is better to check first using __getattribute__, which is always defined, and to fallback to _getattr_ if it fails.

I suggest doing this if you don't know in advance if the base class implements a custom __getattr__ method:

def __getattr__(self, name):
    try:
        buffer = self.__getattribute__('_ubuffer')
    except AttributeError:
        try:
            buffer = super().__getattr__('_ubuffer')
        except AttributeError:
            raise AttributeError('Attribute {} not found.'.format(name))

    if name in buffer.dtype.names:
        return buffer.data[name]
    raise AttributeError('Attribute {} not found.'.format(name))

But in most cases, just using __getattribute__ should be enough:

def __getattr__(self, name):
    try:
        buffer = self.__getattribute__('_ubuffer')
        if name in buffer.dtype.names:
            return buffer.data[name]
        raise AttributeError
    except AttributeError:
        raise AttributeError('Attribute {} not found.'.format(name))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.