1. 程式人生 > >python3 中類的面向物件特性

python3 中類的面向物件特性

封裝,繼承,多型,動態生成類

封裝

python類中的封裝特性是通過命名來實現的

  • private 用雙下劃線開頭,表示變數或者函式只在當前類中可見
  • protect 用單下劃線開頭,表示變數或者函式只在當前類以及其子類中可見
  • public 不以下劃線開頭,表示變數或者函式可以在任意類中使用

繼承

  1. 繼承多個類

    class myClass(cls1,cls2):
        pass
    
  2. super機制

  • super() 函式用於呼叫下一個父類(超類)並返回該父類例項的方法。

  • 直接用類名呼叫父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查詢順序(MRO)、重複呼叫(鑽石繼承)等種種問題。總之前人留下的經驗就是:保持一致性。要不全部用類名呼叫父類,要不就全部用 super,不要一半一半。

    super(type[, object-or-type])type指的是子類,object-or-type一般是self
    
  1. 經典類和新式類的方法解析順序(MRO,Method Resolution Order)

    • 經典類,類自身或者其 Python 2.x中預設都是經典類,只有顯式繼承了object才是新式類,但是在Python 3.x中按照如下寫法,仍然會被認為是新式類

      class A:
          pass
      
    • 新式類,類自身或者其父類繼承了object則為新式類。 Python 3.x中預設都是新式類,不必顯式的繼承object

      class A(object):
          pass
    • 經典類解析原則
      從左至右的深度優先遍歷,但是如果遍歷中出現重複的類,保留第一個
      舉例:

    class G:attr = 1
    class P1(G): pass
    class P2(G): attr = 2
    class D(P1,P2): pass
    # attr的順序為[D,P1,G,P2,G]
    # 因為重複的類只保留第一個,所以最終的解析順序為[D,P1,G,P2]
    print(D.attr)
    
    • 新式類解析原則
      新式類和經典類一樣都是從左至右的深度優先遍歷,但是如果遍歷中出現重複的類,只保留最後一個
      舉例:
    class G1(object): attr = 1
    class G2(object
    ): attr = 3 class P1(G1,G2): pass class P2(G1,G2): attr = 2 class D(P1,P2): pass # attr順序為[D,P1,G1,G2,P2,G1,G2] # 因為重複的類只保留最後一個,所以最終解析順序為[D,P1,P2,G1,G2] print(D.attr) # 輸出為2
    • 新式類多重繼承容易出錯的位置
      如果C繼承的兩個類P1和P2都繼承了相同的類,但是P1和P2的MRO順序不一樣的話,會報錯
      • 類的示例圖
          (object)
      	 /   \
      	G1   G2
      
      P1(G1,G2) P2(G2,G1)
          \      /
      	C(P1,P2)
      
      • 例項
      class G1(object): attr = 1
      class G2(object): attr = 3
      class P1(G1,G2): pass
      class P2(G2,1): attr = 2
      class D(P1,P2): pass
      #P1的MRO順序為[P1,G1,G2]
      #P2的MRO順序為[P2,G2,G1]
      print(D.attr) # 輸出報錯
      
      • 報錯資訊:
      Traceback (most recent call last):
        File "mro.py", line 4, in <module>
          class P2(G2,1): attr = 2
      TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
      
  2. __new__函式和__init__函式

    • __new__函式是例項化類的時候呼叫的,為__init__函式提供類物件,也就是__init__函式的第一個引數,所以_new__函式必須返回類物件,通常可以用super(A,cls)._new(cls)獲取
    • __init__函式是初始化物件的時候呼叫的,其中的self引數即是__new__函式返回的。

多型

  • 類具有繼承關係,並且子類型別可以向上轉型看做父類型別,如果父類中有這種方法,只要傳入相應引數就可以使用。

  • 開閉原則

    • 對擴充套件開放(Open for extension):允許子類重寫方法函式
    • 對修改封閉(Closed for modification):不重寫,直接繼承父類方法函式
  • __call__函式

    • 作用是把類的例項當作函式進行呼叫
    • 舉例
      class Fib(object):
          def __call__(self,num):
              return num
          
      f = Fib() # 此處f是類的例項
      print f(10) # 此處把類的例項當成函式在用,實際上進行處理的就是__call__函式
      

動態生成類

  1. 類物件的型別,python中一切都是物件,類也是物件,如果是類,則為type。如果是物件,其型別的型別也還是type

    >>> class MyCls(object):pass
    ... 
    >>> MyCls.__class__
    <class 'type'>
    >>> a=379
    >>> a.__class__
    <class 'int'>
    >>> a.__class__.__class__
    <class 'type'>
    >>> a.__class__.__class__.__class__
    <class 'type'>
    
  2. type 函式,動態生成類

    type(類名, 父類的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))
    

    舉例

    >>> class pClass(object):pass
    ... 
    >>> child=type('ChildClass',(pClass,),{})
    >>> child.__name__
    'ChildClass'
    >>> child.__class__
    <class 'type'>
    
  3. 使用metaclass,生成動態類

    • metaclass 作用
    • metaclass的呼叫順序

    類Foo中有metaclass這個屬性嗎?如果是,Python會在記憶體中通過metaclass建立一個名字為Foo的***類物件***(我說的是類物件)。如果沒有找到metaclass,會在(父類)中繼續尋找metaclass屬性,並嘗試做和前面同樣的操作。如果還是找不到metaclass,Python就會用內建的type來建立這個類物件。

    • metaclass 使用方法
      • 首先自定義metaclass,繼承type。
      • 在自定義元類中的__new__函式中返回自定義類,也就是type(class_name,class_parents,class_attr)。
      • 在想使用元類的類定義中設定metaclass屬性為目標元類。
    • metaclass例項
    class myMetaClass(type):
        def __new__(metaname, class_name, class_parents, class_attr):
            print("Hello hello")
            return super(myMetaClass,metaname).__new__(metaname, class_name, class_parents, class_attr)
    class Foo(object,metaclass=myMetaClass):
        pass
    
    f = Foo()
    print(type(Foo))
    

    輸出

    Hello hello
    <class '__main__.myMetaClass'>
    

擴充套件題

  • ORM是如何實現的(程式碼在連線,by 廖雪峰)
    • 描述器
    • 動態生成類