組合,Mixin,類、類對象、實例對象
1、組合,將幾個橫向關系的組合在一起。所謂的組合就是將類的實例化放到新類裏面,那麽就將舊類組合進去了。
class Turtle: def __init__(self, x): # 註意 init 前面必須雙下劃線 self.num = x class Fish: def __init__(self, x): self.num = x class Pool: def __init__(self, x, y): self.turtle = Turtle(x) # Pool類中實例化Turtle對象self.fish = Fish(y) def print_num(self): print(‘水池中共有烏龜 %d 只,小魚 %d 條!‘%(self.turtle.num,self.fish.num))
調用結果:
pool = Pool(2, 7) >>> pool.print_num() 水池中共有烏龜 2 只,小魚 7 條!
**:在新類中實例化舊類,如:self.turtle = Turtle(x) ,個人理解為將 Turtle 對象傳遞給 self.turtle 對象(屬性),然後self.turtle 對象就具有Turtle 對象的屬性了(體現在實例化 Pool 對象後,可以調用self.turtle.num,num 在 Pool 類中是沒有定義的
2、Mixin 簡介
Mixin 編程是一種開發模式,是一種將多個類中的功能單元的進行組合的利用的方式,這聽起來就像是有類的繼承機制就可以實現,然而這與傳統的類繼承有所不同。通常 Mixin 並不作為任何類的基類,也不關心與什麽類一起使用,而是在運行時動態的同其他零散的類一起組合使用。
特點
使用 Mixin 機制有如下好處:
- 可以在不修改任何源代碼的情況下,對已有類進行擴展;
- 可以保證組件的劃分;
- 可以根據需要,使用已有的功能進行組合,來實現“新”類;
- 很好的避免了類繼承的局限性,因為新的業務需要可能就需要創建新的子類。
多繼承
Python支持多繼承,即一個類可以繼承多個子類。可以利用該特性,可以方便的實現mixin繼承。如下代碼,類A,B分別表示不同的功能單元,C為A,B功能的組合,這樣類C就擁有了類A, B的功能。
class A: def get_a(self): print ‘a‘ class B: def get_b(self): print ‘b‘ class C(A, B): pass c = C() c.get_a() c.get_b()
__bases__
多繼承的實現就會創建新類,有時,我們在運行時,希望給類A添加類B的功能時,也可以利用python的元編程特性,__bases__屬性便在運行時輕松給類A添加類B的特性,如下代碼:
A.__bases__ += (B,) a.get_b()
其實__bases__也是繼承的機制,因為__bases__屬性存儲了類的基類。因此多繼承的方法也可以這樣實現:
class C: pass C.__bases__ += (A, B, )
插件方式
以上兩種方式,都是基於多繼承和python的元編程特性,然而在業務需求變化時,就需要新的功能組合,那麽就需要重新修改A的基類,這回帶來同步的問題,因為我們改的是類的特性,而不是對象的。因此以上修改會對所有引用該類的模塊都收到影響,這是相當危險的。通常我們希望修改對象的行為,而不是修改類的。同樣的我們可以利用__dict__來擴展對象的方法。
class PlugIn(object): def __init__(self): self._exported_methods = [] def plugin(self, owner): for f in self._exported_methods: owner.__dict__[f.__name__] = f def plugout(self, owner): for f in self._exported_methods: del owner.__dict__[f.__name__] class AFeature(PlugIn): def __init__(self): super(AFeature, self).__init__() self._exported_methods.append(self.get_a_value) def get_a_value(self): print ‘a feature.‘ class BFeature(PlugIn): def __init__(self): super(BFeature, self).__init__() self._exported_methods.append(self.get_b_value) def get_b_value(self): print ‘b feature.‘ class Combine:pass c = Combine() AFeature().plugin(c) BFeature().plugin(c) c.get_a_value() c.get_b_value()
3、類、類對象、實例對象
class C: count = 0 >>> a = C() >>> b = C() >>> c = C()
>>>a.count
0 >>> c.count += 10 >>> a.count 0 >>> b.count 0 >>> C.count += 100 >>> a.count 100 >>> b.count 100 >>> c.count 10
1)python中無處不對象。類中定義的屬性時靜態屬性,類屬性和類對象是綁定的,不依賴於實例對象。
2)實例化對象後,進行實例對象屬性的修改不會影響類對象的屬性,所以 c.count += 10不會影響 C.count 的值。
3)修改類對象屬性屬性之後,實例化對象的屬性也會跟著改變,註意,經過實例對象修改過的屬性不隨著類屬性的改變而改變(見上邊染色部分代碼),原因:個人理解為此處類似變量間的復制,實例對象是一個標簽,和類對象指向同一個類屬性地址,所以:a)類屬性改變,實例對象屬性跟著改變;b)單獨修改實例對象屬性是從新開辟堆棧,覆蓋了該實例對象原本的類屬性,所以這個修改不影響類屬性,修改類屬性也不影響經過修改的實例對象屬性。
4、如果屬性名稱和方法名稱一樣,屬性名稱會覆蓋方法名稱。如下:給實例對象 c 定義 x 屬性之後,再調用 x() 方法會報錯。
組合,Mixin,類、類對象、實例對象