Python:Metaclass属性有时会覆盖类属性?

时间:2014-03-23 02:28:07

标签: python metaclass

以下代码的结果令我难以理解:

class MyClass(type):
    @property
    def a(self):
        return 1

class MyObject(object):
    __metaclass__ = MyClass

    a = 2

print MyObject.a
print object.__getattribute__(MyObject, 'a')
print type.__getattribute__(MyObject, 'a')
print MyObject.__dict__['a']
print MyObject().a

我真的希望这只是重复打印2,但会打印1 1 1 2 2。有没有一种方法可以直观了?


澄清:我理解这种行为已有详细记录(here, "data descriptors"),但我想了解为什么这有意义,以及为什么核心开发人员以这种方式实现描述符。

2 个答案:

答案 0 :(得分:1)

属性为data descriptors;在属性查找中,它们优先于具有该属性的类的实例的dict中具有相同名称的条目。这意味着用

MyObject.a

a中的MyClass属性优先于a dict中的MyObject条目。类似地,

object.__getattribute__(MyObject, 'a')
type.__getattribute__(MyObject, 'a')

object.__getattribute__type.__getattribute__都尊重数据描述符优先于实例dict条目,因此属性获胜。

另一方面,

MyObject.__dict__['a']

这明确地执行了dict查找。它只能看到MyObject的dict中的内容,忽略了正常的属性查找机制。

最后一行:

MyObject().a

MyClass描述符仅适用于MyClass的实例,而不适用于其实例的实例。属性查找机制看不到属性。

答案 1 :(得分:-1)

以下是一些非常相似的代码,可以帮助您了解正在发生的事情

class MyClass(object):
    def __init__(self, data):
        self.__dict__.update(data) # this would fail if I had self.a = a

    @property
    def a(self):
        return 1

MyObject = MyClass({'a': 2})

print MyObject.a
print object.__getattribute__(MyObject, 'a')
print MyObject.__dict__['a']

您所看到的是实例(类)在其类上具有描述符(您的属性)和具有相同名称的属性。通常情况下,有保护措施可以保护这一点,但type的工作方式可以解决这些问题。

所以你有

 print MyObject.a

描述符击败__dict__条目并调用property。这是因为object.__getattribute__的实施,至少在概念上。

 print object.__getattribute__(MyObject, 'a')

这与说MyObject.a是一回事,除非object.__getattribute__被覆盖。 __getattribute__是尝试描述符的行为首先来自的地方。

 print type.__getattribute__(MyObject, 'a')

这与object.__getattribute__相同,因为type并不覆盖__getattribute__

 print MyObject.__dict__['a']

这会在__dict__中查找,这是您存储2的唯一地方。这只是一个dict对象(可能/几乎),所以它不会在其他任何地方查找。

 print MyObject().a

该属性的工作方式,您不会以与直接相同的方式访问您的类型属性。这可能是没有超直观答案的部分

相关问题