以下代码的结果令我难以理解:
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"),但我想了解为什么这有意义,以及为什么核心开发人员以这种方式实现描述符。
答案 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
该属性的工作方式,您不会以与直接相同的方式访问您的类型属性。这可能是没有超直观答案的部分