2013-07-13 94 views
3

有這樣的代碼:爲什麼__get__方法不被實例屬性調用?

class A: 
    def __init__(self, x): 
    self.x = x 

    def __get__(self, obj, type=None): 
    print("__get__") 
    return self.x 

    def __set__(self, obj, value): 
    pass 

class B: 
    a_oc = A(44) 
    def __init__(self, y): 
    self.a_ob = A(y) 

b = B(3) 
print(b.a_oc) # class attribute called __get__ 
print(b.a_ob) # __get__ not called 

對於類屬性__get__被調用,比如屬性事實並非如此。爲什麼?

+0

你確定嗎?我只是運行這個代碼,而沒有'__get__'打印到我的控制檯。 –

+0

我用Python 3.3試過它,它是 – scdmb

+2

啊,NM,我能夠在Python 3.2中複製它,但不是Python 2.7 –

回答

2

爲新的類型的類屬性查找規則(在3 x和類類從在2.x的對象繼承),則採取obj.attr

  1. 如果被Python,這樣產生的值爲__hash__,返回它

  2. 查找在obj.__class__.__dict__,如果它存在和存在__get__,在父類中遞歸返回結果的attr.__get__(obj, obj.__class__),如果沒有,查找。

  3. 查找在obj.__dict__。如果obj是一個實例並且存在attr,則返回它或下一步。否則,如果obj是一個類,則查找本身,其父母的__dict__(如果它是描述符),則返回attr.__get__(None, obj.__class__)或attr本身。

  4. 查找obj.__class__.__dict__。如果attr是非數據描述符,則返回它的結果。否則返回attr本身,如果它存在。

  5. 提高AttributeError的

看你等級:

>>> b.__class__ 
<class 'des.B'> 
>>> b.__class__.__dict__ 
mappingproxy({'__init__': <function B.__init__ at 0x7f2dacb4e290>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__dict__': <attribute '__dict__' of 'B' objects>, 'a_oc': <des.A object at 0x7f2dacb5de50>, '__module__': 'des', '__qualname__': 'B'}) 
>>> 
>>> b.__dict__ 
{'a_ob': <des.A object at 0x7f2dacb5df10>} 
>>> 

b.a_oc適合步驟2和步驟b.a_ob適合步驟3。我把你的代碼放在模塊des中。

+0

您發佈的查找規則的順序與第一段相沖突。 – Marcin

+0

衝突在哪裏?@Marcin – zhangyangyu

+0

第一段暗示實例'__dict__'中的存在將搶佔對'__get__'的調用,但是您首先調用__get__'。澄清是必需的。另外,你的第一條規則是模糊的,以至於毫無意義。最後,請說明這些規則的來源,以及這是否僅適用於Python 3. – Marcin

相關問題