在带有数据描述符的 class 上使用 getattr

Use of getattr on a class with data descriptor

在构建 classes 时使用数据描述符时,我在 class.

上遇到了 getattr 函数的奇怪行为
# this is a data descriptor
class String(object):
    def __get__(self, instance, owner):
        pass
    def __set__(self, instance, value):
        pass

# This defines a class A with 'dot' notation support for attribute 'a'
class A(object):
    a = String()

obj = A()
assert getattr(A, 'a') is A.__dict__['a']
# This raises AssertionError

LHS return 一个空字符串,而 RHS return 是 String 的一个实例。我认为对象上的 getattr 是获取 __dict__ 中的键的值。 getattr 函数如何作用于 class 对象?

getattr(A, 'a') 触发描述符协议,即使在 类 上也是如此,因此调用 String.__get__(None, A)

那个 returns None 因为你的 String.__get__() 方法没有明确的 return 语句。

来自Descriptor Howto

For classes, the machinery is in type.__getattribute__() which transforms B.x into B.__dict__['x'].__get__(None, B).

getattr(A, 'a') 只是 A.a 的动态,所以 A.__dict__['x'].__get__(None, A) 被执行,这就是为什么你没有得到与 A.__dict__['x'] 相同的东西。

如果您希望它 return 描述符对象本身,则必须 明确地 这样做;在这种情况下,instance 将设置为 None

class String(object):
    def __get__(self, instance, owner):
        if instance is None:
            return self
    def __set__(self, instance, value):
        pass

这就是 property 描述符对象的作用。

请注意,descriptor.__get__owner 参数是可选的;如果没有设置,你应该使用 type(instance) 代替。

getattr(A, 'a') 等同于 A.a。这将调用相应的描述符(如果存在)。所以它提供了描述符呈现的值,也就是None