1. 程式人生 > >組合,Mixin,類、類對象、實例對象

組合,Mixin,類、類對象、實例對象

方便 .com 子類 然而 覆蓋 屬性 pen 一個 代碼

  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,類、類對象、實例對象