2012-02-14 52 views
2

所以我有這樣的:特殊性覆蓋的屬性二傳手

class Parent(object): 

    def __init__(self, val): 
     print 'enter Base init' 
     self._set_x(val) 
     print 'leave Base init' 

    def _get_x(self): 
     return self._x 

    def _set_x(self, val): 
     print 'enter Base _set_x' 
     self._x = val 
     print 'leave Base _set_x' 

    x = property(_get_x, _set_x) 

class Child(Parent): 

    def _set_x(self, val): 
     print 'enter Child _set_x' 
     y = val * 2 
     super(Child, self)._set_x(y) 
     print 'leave Child _set_x' 

child = Child(5) 
num = child.x 
child.x = 5 
print num == child.x 

當我運行它,我得到這個:

enter Base init 
enter Child _set_x 
enter Base _set_x 
leave Base _set_x 
leave Child _set_x 
leave Base init 
enter Base _set_x 
leave Base _set_x 
False 

我一直在看四周,人們說壓倒一切不應該工作,但我的問題是爲什麼這裏看起來不一致呢?當從init調用子類時,子類的setter會被調用,但是當你稍後作用於已經初始化的對象時,它會調用基礎的setter。有人可以解釋這裏發生了什麼嗎?

回答

5

因爲你稱它不一致 - 一次直接,一次通過屬性。將Parent.__init__中的self._set_x(x)更改爲self.x = x,您將看到Child._set_x從未被調用過。要覆蓋在子類中的二傳手,你可以使用property.setter作爲裝飾:

class Child(Parent): 
    @Parent.x.setter 
    def x(self, arg): 
     super()._set_x(arg) 

或者增加一個間接的級別屬性:

class Parent(object): 
    # ... 
    x = property(
     lambda self: self._get_x(), 
     lambda self, x: self._set_x(x) 
    ) 

壓倒一切的不直接工作,因爲財產存儲具體方法對象(Parent._get_xParent._set_x),並且不會再次查找它們,即使對象的類型發生更改 - 運行的代碼無論如何都是相同的。間接強制在self的動態類型中查找,這可以覆蓋。

+0

啊,我明白了。因爲即使在父母的初始範圍內,它仍然會看着設置者的完整的孩子自我。我在想,基類的init方法在沒有額外工作的情況下不會找到孩子的setter,但現在我想到了它,當然這是有道理的。謝謝。 – 2012-02-14 19:26:45

2
x = property(_get_x, _set_x) 

這裏x成爲吸氣劑Parent._get_x和setter Parent._set_x的屬性。

如果將行x = property(Parent._get_x, _set_x)添加到Child類中,該屬性將被重新定義並且將按預期工作。

+0

儘管這只是一個問題。我編輯了這個問題,以消除錯誤的名稱混淆。 – 2012-02-14 19:21:00

0

將方法看作對象。父類的屬性x已綁定到父類的_get_x/_set_x方法對象。但是在你的Child類中,你正在調用該類自己的_set_x方法對象。

3

沒有不一致。 __init__方法通過屬性查找顯式調用self._set_xself這裏指的是Child對象,並且由於Child定義爲_set_x,並且Child類首先位於對象的Method Resolution Order(MRO)中,因此它的版本_set_x是被調用的版本。

x屬性在Parent內定義。目前還沒有孩子參與,因此版本_set_x和傳遞給property的版本是Parent中定義的版本。現在,當訪問Childx屬性時,Python首先在Child類中查找x。但它沒有找到它,因爲Child沒有定義它。然後進入MRO的下一課:Parent。它在那裏找到x,並按照Parent中的定義使用它。

+0

是的,你和@Cat Plus Plus有相同的點。謝謝。 :) – 2012-02-14 19:28:46