为什么在 hassattr() 内部调用 Python 中描述符的 __get__ 方法?

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

假设

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()

然后在调用 hasattr(c,"d1") 期间调用 C.d1__get__ 方法。为什么? hasattr() 不应该查字典吗?

在交互式 CPython-version-3.6.10-session 中按下 <tab> 完成时会发生相同(但更奇怪),如 c.d<tab>。在这种情况下, __get__ 将针对除最后一个之外的所有匹配属性调用。 这是怎么回事?

如果您查看 hasattrhelp(或 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.

所以不,它不只是“检查字典”,它不能那样做,因为并非所有对象都以字典作为名称空间开头,例如built-in 个对象,或 user-defined 个对象 __slots__.

getattr(obj, name) 将正确调用等价的机器:

obj.name

这会调用描述符的 __get__

不确定制表符是否完成,但 hasattr 确实调用了 __get__。是 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.)