2016-06-01 162 views
0

我知道如何初始化一個父類,以便在子類中獲得它們的實例屬性,但不完全是幕後操作來實現這一點。 (注意:這裏不是特意使用,只是爲了說明清楚)初始化父類實例的屬性

下面我們通過給孩子class B增加一個額外的屬性y來擴展class A。如果您在實例化b=B()後查看課程詞典,我們正確地看到b.x(繼承自class A)和b.y

我認爲在class B__init__內的較高水平,這是通過調用A.__init__(self,x=10)執行類似b.x=10(正常實例屬性將被分配的方式)的東西來完成。這對我來說有點不清楚,因爲你打電話class A__init__,而不是class B,但class B仍然得到它的實例屬性相應地更新。 class A's__init__如何知道更新b's實例屬性。

這與繼承方法不同,其中b對象在其特定名稱空間中沒有顯式繼承方法,但在調用缺少方法時查找繼承鏈。使用該屬性,該方法實際上是在b的名稱空間(它是實例字典)。

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

    class B(A): 
     def __init__(self): 
      A.__init__(self,x=10) 
      self.y = 1 

    b = B() 
    print(b.__dict__) 
    >>>{x:10,y:1} #x added to instance dict from parent init 

下面我們從內建列表繼承。在這裏,與上面類似,由於我們在Foolist的__init__中調用列表的__init__方法,我期望看到包含elems的實例字典,但它無處可查。值123位於對象的某處,如通過打印alist可以看到的,但不在實例字典中。

class Foolist(list): 
    def __init__(self, elems): 
     list.__init__(self, elems) 

alist = Foolist('123') 

那麼究竟是怎麼回事在繼承類時,父母的__init__從孩子的__init__叫什麼名字?價值如何被約束?這與查找方法有所不同,因爲您不是按需搜索繼承鏈,而是實際將值分配給繼承類的實例dict。

如何給父母init調用填寫它的孩子的實例字典?爲什麼愚蠢的例子不這樣做?

回答

2

答案很簡單:self

作爲一個非常粗略的概述,當實例化一個類時,對象被創建。這或多或少只是一個空容器,沒有任何關係。*這個「空容器」然後被傳遞給被實例化的類的__init__方法,它變成...... self參數!然後你在那個對象上設置一個屬性。您然後調用不同類的__init__方法,明確地將您的特定self對象傳遞給該方法;該方法然後向對象添加另一個屬性。

這實際上是每個實例方法的工作原理。每個方法隱含地接收「當前對象」作爲其第一個參數,self。當調用父級的__init__方法時,實際上是讓該對象非常明確地傳遞。

可以近似用這個簡單的例子,行爲:

def init_a(obj): 
    obj.x = 10 

def init_b(obj): 
    init_a(obj) 
    obj.y = 20 

o = {} 
init_b(o) 

*的對象不完全是「空」的,也有其創建的從屬關係與特定的類對象上設置特定屬性,因此該對象是某個類的「實例」,並且Python可以根據需要找到它從類繼承的所有方法。