2016-05-20 209 views
0

我有一個類定義了'alarm',然後一個定義了'httpalarm'。現在httpalarm與警報共享許多相同的屬性(實際上它們都具有相同的屬性,以及其他屬性)。對象繼承父對象的屬性

我認爲我應該可以做的就是將這些屬性定義爲警報對象的一部分,然後當httpalarm被創建爲警報子時,它應該已經獲得所有屬性。但事實並非如此。至少,似乎沒有;

class alarm(object): 
    def __init__(self, severity, name, eventId): 
     self.severity = severity 
     self.name = name 
     self.eventId eventId 


class httpalarm(alarm): 
    def __init__(self, **kwargs): 
     self._dict__.update(kwargs) 

現在,當我創建一個報警對象我得到了我期望:

a = alarm('Critical', 'Name', '0x800111') 

vars(a) 
-> 
{'severity': 'Critical', 'name': 'Name', 'eventId': '0x800111'} 

這是符合市場預期。但是,當我創建一個httpalarm:

b = httpalarm(test = 'Test') 
vars(b) 
-> 
{'test': 'Test'} 

這是意想不到的。我期待httpalarm b也會設置嚴重性,名稱和eventId屬性。沒有改變httpalarm我再測試一次

class alarm(object): 
    severity = 'Warning' 
    name = None 
    eventId = None 

然後;:

因此,而不是實例的屬性,我設置爲使用類屬性報警類別

c = httpalarm(test='Test') 

vars(c) 
-> 
{'test': 'Test'} 

此外,變量不顯示所有其他屬性。但是,他們正在被設定爲;

print c.severity 
'Warning' 

打印繼承屬性似乎工作。並且還使用dir(c)來顯示對象的確會返回所有屬性

dir(c) 
-> 
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eventId', 'name', 'severity', 'test'] 

我不太確定這裏發生了什麼。我想創建一個可以繼承的警報類,以免我必須始終定義相同的屬性。我想要得到的是:

d = httpalarm(severity = 'Critical', name = 'Name', eventId = '0x800111', test = 'test') 

,並有httpalarm實例ð包括報警的所有屬性,以及其自己的httpalarm類的屬性。

編輯: 繼從科利Brigman提交我有這個工作作爲工作用料:

class httpalarm(alarm): 
    def __init__(self, 
       **kwargs): 

     super(httpalarm, self).__init__() 
     for k,v in self.__dict__.iteritems(): 
      if type(v) == tuple: 
       setattr(self, k, v[0]) 

     self.__dict__.update(kwargs) 

回答

1

您需要自行調用alarm的構造:

class httpalarm(alarm): 
    def __init__(self, **kwargs): 
     super(httpalarm, self).__init__() 
     # Your code here 

爲什麼這在這裏特別需要? Python的對象實現與C++和Java等其他語言有很大不同,它必須在如何創建對象方面做很多事情。

C++對象基本上是一個內存結構,它附帶了一些函數。一個Python對象更像是一個附帶了一些函數的字典。這是如何發揮出來的?

在這兩種環境中,你能想象的創作(new,但通常落後於C++的場景; __new__如Python中的類的功能),以及初始化(C++中的構造函數,在Python __init__)兩個分開的部分。

在C++中,由於內存結構對於對象的操作至關重要,所以當您調用new(高級別)時,系統會爲每個用正確大小聲明的屬性分配空間。這是靜態的 - 您無法即時創建新屬性,只能修改您聲明的屬性。請注意,這也需要當你繼承子類時,你也正在聲明結構將是什麼樣的 - 所以編譯器可以構建正確的內存映像。

然後,你調用構造函數,它實際上基於輸入和程序員想要的值初始化值。在許多情況下,如果您對使用初始化的默認值感到滿意,您實際上可以將構造函數放在C++中,或者聲明它,但保留爲空。

在Python中,由於對象模型更像是一個可變字典,因此基類行爲('創建字典並附加到對象')是創建該字典。對於大多數用途來說,這通常是足夠的,所以在Python中,你幾乎不會看到用(*)寫的函數。

相反,大多數人的默認設置是初始化__init__函數中的變量。重要的是這個被稱爲之後對象被創建。然後,你可以設置你想要的任何變量,無論你想要的任何數據類型。

重要的是,在這兩種情況下,在調用初始化程序之前在之前創建對象。在C++中,創建會創建數據結構。在Python中,對象創建(通常)只是創建一個字典 - 在alarm.__init__httpalarm.__init__的條目處,這兩個對象看起來就像一個空字典。 init必須創建必要的屬性。在C++中調用基類構造函數並不罕見,但在Python中更常見,因爲基類構造函數也創建了子類使用的公共屬性。

您可以使用插槽 - 它們更接近於C++的工作方式,但不完全如此。

對於vars - vars只顯示當地屬性 - 你在__init__或其他地方設置的。當你將它們聲明爲類變量時,它們將顯示在dir中,因爲它顯示了類屬性和本地設置的對象屬性,但不是vars。從文檔字符串:

vars([object]) -> dictionary 

Without arguments, equivalent to locals(). 
With an argument, equivalent to object.__dict__. 

類變量是object.__class__.__dict__而不是object.__dict__

如果您確實需要這種行爲,您可以使用元類,並覆蓋__new__函數來創建一些默認屬性。這並不常見,但它更像C++(據我所知......我也沒有那麼做)。但它有時會做(通常稱爲「元編程」或類似的東西),特別是如果你想要動態屬性,因爲屬性(必然)是屬性,並且不能在對象上動態設置;相反,您使用一個類工廠,它動態地添加所需的屬性。