2014-10-11 59 views
4

嗯,我幾乎一樣question,除了一個細節:我需要獲得基類的私有值。代碼:從子類獲取父私有或受保護的值

class Parent(object): 
    def __init__(self): 
     self.__field = 13  

class Child(Parent): 
    """docstring for Child""" 
    def __init__(self): 
     super(Child, self).__init__() 

    def ChildMethodWhichUsingParentField(self): 
     return self.__field 

if __name__ == '__main__': 
    c = Child() 
    c.ChildMethodWhichUsingParentField() 

解釋輸出:

Traceback (most recent call last): 
    File "foo.py", line 20, in <module> 
    c.ChildMethodWhichUsingParentField() 
    File "foo.py", line 16, in ChildMethodWhichUsingParentField 
    return self.__field 
AttributeError: 'Child' object has no attribute '_Child__field' 

的問題是,解釋試圖讓_Child__field當我需要_Parent__field。我可以使用@property得到這個值,但它會制動封裝。此外,我可以解決這個問題寫self._Parent__field但這是醜陋的,顯然是錯誤的代碼。還有其他方法嗎?

+3

你爲什麼不停止在兩個下劃線前加'field'? – jonrsharpe 2014-10-11 20:27:03

+0

單個下劃線是一種類型的定製「私人」成員。 – 2014-10-11 20:36:48

+0

@jonrsharpe,因爲這會制動封裝。 '領域'是重要的,僅供內部使用。我想確保沒有人能看到和/或修改'field'。 – Montreal 2014-10-11 20:39:45

回答

2

正如您在問題所指出的,你可以獲得通過明確使用其名稱的錯位的形式在子類的父屬性:

def ChildMethodWhichUsingParentField(self): 
    return self._Parent__field 

這是您直接提問的唯一簡單答案。

但是,如果您可以控制Parent類,那麼這將是一個非常糟糕的設計。您不應該使用雙下劃線屬性名稱來表示另一個類類將會使用的內容(並且即使您不期望這種用法,您也可能不應該使用它)。改爲使用單個下劃線(_field)。這個「文檔」表明該屬性是私有的(例如不是類的公共API的一部分),而不啓用名稱修改。這樣,如果你發現比其他類晚,需要訪問它可以的變量。 Python不強制隱私(即使使用名稱修飾),所以您始終需要依賴其他代碼行爲良好。

名稱修剪實際上僅用於需要避免名稱衝突的情況。例如,一個代理對象可能會爲其自己的屬性使用重名名稱,以便它可以呈現一個接口,該接口是另一個對象接口(可能不會提前知道)的確切副本。或者一個mixin類可能會使用名稱修飾來表示它的變量,因爲它無法確切地知道哪些屬性名稱將被用在(可能很多)其他類中,這些類將被一起繼承。如果您將自己使用的屬性添加到其他對象(而不是self)並且希望避免錯誤地覆蓋其現有屬性,也會很有用。

+0

有沒有建議強制隱私的任何peps?恕我直言,這是非常大的蟒蛇的缺陷。甚至比低速更大。 – Montreal 2014-10-11 22:02:40

+2

@Montreal:Python開發者社區並沒有將缺乏隱私執法視爲一個缺陷。的確,這是一個功能。如果你真的需要,你可以進入並修改任何東西。當事情沒有按照你期望的那樣進行時,這非常有用,並且你想要將日誌記錄注入到現有的類中,或者反思某些內容來調試奇怪的行爲。 – Blckknght 2014-10-11 22:08:19

+0

非常感謝。 – Montreal 2014-10-11 22:11:57

1

這是通過添加一個getter

class Parent(object): 
    def __init__(self): 
     self.__field = 13 

    def get_field(self): 
     return self.__field 

class Child(Parent): 
    """docstring for Child""" 
    def __init__(self): 
     super(Child, self).__init__() 


    def ChildMethodWhichUsingParentField(self): 
     return self.get_field() 

if __name__ == '__main__': 
    c = Child() 
    print c.ChildMethodWhichUsingParentField() 
相關問題