Hasattr(self, x) v.s. x in dir(self)

Hi there

I have had no doubt using hasattr. But recently, I tripped on a small piece of stone.

I want to check whether foo attribute exists in the derived class. If hasattr is used, the derived class property foo is executed unnecessarily. So I started thinking that if there’s a possibility that the attribute to check is a property, it should be replaced with the “x in dir()” idiom (although I don’t like such mixtures)…

class Base(object):
    def __init__(self):
        ## According to the Python documentation:
        ## <https://docs.python.org/3/library/functions.html#hasattr>
        ## This is implemented by calling getattr(object, name) and seeing 
        ## whether it raises an AttributeError or not.
        print(hasattr(self, 'foo')) # False. foo<property> is called.
        print('foo' in dir(self)) # True. foo<property> is not called.

class Device(Base):
    def __init__(self):
        super().__init__()
        self.bar = 0

    @property
    def foo(self):
        print("foo is called.")
        return self.bar

Device()

My question is, is there any problem in replacing hasattr with x in dir()?
If no, a further question I would like to ask is why hasattr was not implemented by x in dir().

yes, see note

2 Likes

Hello buddy, thank you so much! You saved me from going down the wrong path :smiling_face_with_three_hearts:

What I wanted to achieve was to check the derived class attributes without executing the property getter.

The next idea that comes to mind is:

def _hasattr(self, name):
    return hasattr(type(self), name) or hasattr(self, name)

I’m not sure that this would be the best solution.
Any ideas I would appreciate.

1 Like

Seems like that’s indeed the best solution availible; I explored a few other possible approaches, but they all were either less clean, simple and robust, or still executed the property code.

2 Likes

I was surprised by this. … So much to learn about attribute access.

This is going to return wrong results for metaclass descriptors, most notably mro:

>>> a = object()
>>> _hasattr(a, 'mro')
True
>>> a.mro()
AttributeError: 'object' object has no attribute 'mro'
1 Like

As suggested on the linked SO thread, a fix might be something like:

def _hasattr(self, name):
    return isinstance(getattr(type(self), name, None), property) or hasattr(self, name)
1 Like

That wouldn’t completely nicely play with non-property descriptors like functools.cached_property. The only truly robust way is to call hasattr(self, name) (and even that assumes that the object is sane and doesn’t delete the attribute after an access, doesn’t randomly decide what attributes exists, isn’t modified concurrently, …). In general, you should assume that your properties are accessed repeatably and they should not have side effects.

For added fun: a property can itself emit AttributeError. One con
imagine doing so deoiberately for some property which is only present in
some circumstances.

This bites me frequently during dev, as any attribute related error in
the property implementation (including deeper things which it calls)
causes the property to appear not to exist. Same with a __getattr__. I
have a few classes with dynamic attributes depending on their state.

Cheers,
Cameron Simpson cs@cskk.id.au

inspect.getattr_static typically works in cases like this. I’m on mobile and cannot test this exact case, though.

2 Likes