Search code examples
pythonpython-3.xpython-descriptors

Why __get__ method of a descriptor in Python is called inside of hassattr()?


Suppose

class D:
    def __init__(self,id): self.id = id

    def __get__(self,obj,type=None):
        print(self.id,"__get__ is called")

class C:
    d1 = D(1)
    d2 = D(2) 
    d3 = D(3)

c = C()

then during the call hasattr(c,"d1") the __get__ method of C.d1 is called. Why? Shouldn't hasattr() just check the dictionaries?

The same (but weirder) happens when <tab> is presses for completion in an interactive CPython-version-3.6.10-session, as in c.d<tab>. In this case __get__ will be called for all matching attributes except the last one. What is going on here?


Solution

  • If you look at the help for hasattr (or the documentation:

    Help on built-in function hasattr in module builtins:
    
    hasattr(obj, name, /)
        Return whether the object has an attribute with the given name.
    
        This is done by calling getattr(obj, name) and catching AttributeError.
    

    So no, it doesn't just "check dictionaries", it couldn't do that because not all objects have dictionaries as namespaces to begin with, e.g. built-in objects, or user-defined objects with __slots__.

    getattr(obj, name) will correctly invoke the equivalent machinery as:

    obj.name
    

    Which would call the descriptor's __get__