2016-07-11 113 views
3

在我的代碼類A有一個屬性,但類B不會繼承它。 @property是否支持繼承?或者是我的錯?屬性是否支持繼承?

class A(object): 

    def __init__(self): 
     self._x = 100 

    @property 
    def x(self): 
     return self._x 

    @x.setter 
    def x(self, v): 
     self._x = v 


class B(A): 

    @x.setter 
    def x(self, v): 
     self._x = v 

該錯誤消息如下:

Traceback (most recent call last): 
    File "test.py", line 9, in <module> 
    class B(A): 
    File "test.py", line 10, in B 
    @x.setter 
NameError: name 'x' is not defined 
+2

它應該是'@ A.x.setter'。 'x'在這裏是名字空間'A'。 –

+0

你可以繼承一個屬性,但不能單獨修改它。如果你繼承'x'並添加一個setter,那麼原來也會有。您可以再次將屬性定義爲'x'來獲得獨立版本。 –

+0

所以'x'在父對象中是隻讀的,但在子對象中是可讀寫的? – jonrsharpe

回答

2

它只是不知道從哪裏獲取x。你可以這樣做,而不是:

class A(object): 
    def __init__(self): 
     self._x = 100 

    @property 
    def x(self): 
     return self._x 

class B(A): 
    @A.x.setter 
    def x(self, v): 
     self._x = v 
+1

*「當沒有setter時,A()。x = 1將會覆蓋屬性」* - 什麼?你在Python 2.x中試用這個嗎?沒有一個setter屬性是隻讀的,所以給出'AttributeError:不能設置屬性' – jonrsharpe

+0

@jonrsharpe,你是對的。我將A更改爲新風格的類,所以現在對於python2和python3也是如此 –

3

NameError是因爲x是不是在全球範圍內;它在A的類名稱空間中定義,因此您需要使用A.x明確地訪問它。這是一個很常見的錯誤,例如見python subclass access to class variable of parent

雖然屬性可以稍微複雜一些。如果B中添加新的設置器,則使用A.x.setter沒有問題,如Dean's answer中所示。但是,如果您將覆蓋現有的設置器,那麼您也將更改A的行爲。我懷疑這是你想要的行爲。

相反,在這種情況下,您需要在子類中使用A的getter和一個新的setter創建一個新屬性。我認爲這是實現這個最簡單的方法,以最小的重複:

class B(A): 

    x = property(A.x.__get__) # new property with same getter 

    @x.setter # new setter on new property 
    def x(self, v): 
     ... 

注意使用property沒有@語法糖,因爲我沒有用它來裝點一新方法。如果您想從B的二傳手訪問A的二傳手,您可以使用super().x.__set__(whatever)來實現。