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

125 Views Asked by At

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?

2

There are 2 best solutions below

4
On BEST ANSWER

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__

0
On

Not sure about the tab completion, but hasattr does call __get__. It is documented as well:

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 AttributeError or not.)