【问题标题】:Why __get__ method of a descriptor in Python is called inside of hassattr()?为什么在 hassattr() 中调用 Python 中描述符的 __get__ 方法?
【发布时间】:2020-09-17 11:58:11
【问题描述】:

假设

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()不应该只查字典吗?

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

【问题讨论】:

    标签: python python-3.x python-descriptors


    【解决方案1】:

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

    所以不,它不只是“检查字典”,它不能这样做,因为并非所有对象都有字典作为开头的名称空间,例如内置对象,或带有__slots__ 的用户定义对象。

    getattr(obj, name) 将正确调用等效机制:

    obj.name
    

    这将调用描述符的__get__

    【讨论】:

    • 我明白了。这尤其意味着hasattr 在积极结果的情况下与相应的__get__ 一样昂贵。这背后有充分的理由吗?
    • 制表符补全机制在哪里获取要匹配的属性列表?
    • @R.Matveev:描述符的存在并不意味着对象实际上具有相应的属性。判断对象是否具有属性是描述符的工作,描述符可以说不。
    • 例如,如果您使用__slots__ = ('a',) 编写一个类,该类将有一个a 的槽描述符,但如果您尝试访问a 属性,该描述符将引发一个AttributeError在您实际上没有为 a 设置值的实例上。
    【解决方案2】:

    不确定选项卡完成,但hasattr 确实调用了__get__。是documented as well:

    参数是一个对象和一个字符串。结果是True,如果 string 是对象属性之一的名称,False 如果不是。 (这是通过调用getattr(object, name) 并查看 是否引发AttributeError。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-28
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多