1. 程式人生 > >Python 經典類和新式類 super用法 (四)

Python 經典類和新式類 super用法 (四)

在Python2.x的2.2以上版本中,新式類是繼承object的類。

經典類的MRO(基類搜尋順序)演算法是深度優先。

新式類的MRO演算法是C3演算法。

經典類

class A:pass
class B:pass
class C(B):pass
class D(C,A):pass
基類搜尋順序:

D->C->B,->A
[D,C,B,A]

新式類

class A(object):pass
class B(object):pass
class C(B):pass
class D(A,B):pass
class E(C,D):pass

C3演算法:
class B(A1,A2,A3...):pass
mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])
C3演算法的核心是merge演算法(查了半天資料才弄明白)

merge演算法:如果一個序列的第一個元素,是其他序列中的第一個元素,或不在其他序列出現,則從所有執行merge操作序列中刪除這個元素,合併到當前的mro中。

mro(A) = [A,O]
mro(B) = [B,O]

mro(C) = C + merge(mro(B),[B])
= C + merge([B,O],[B])              #merge中的第一個佇列的第一個元素B是後面的元素的第一個元素,所以取出,並刪除所有列表中該元素
= C + B + merge([O])                #第一個佇列後面沒有佇列,所以沒有該元素,所以取出,並刪除所有列表中該元素
= C + B + O
= [C,B,O]

mro(D) = D + merge(mro(A),mro(B),[A,B])
= D + merge([A,O],[B,O],[A,B])       #merge中的第一個佇列的第一個元素A不是後面的元素的第一個元素,但後面列表沒有該元素,所以可以取出,並刪除所有列表中該元素
= D + A + merge([O],[B,O],B)         #merge中的第一個佇列的第一個元素O不是後面的元素的第一個元素,後面佇列中也有該元素,所以不能取出,然後判斷第二個列表的第一個元素(如果還不符合條件,依次處理)
= D + A + merge([O],[B,O],B)         #B是後面的元素的第一個元素,所以取出,並刪除所有列表中該元素
= D + A + B + merge([O],[O])         #O是後面的元素的第一個元素,所以取出,並刪除所有列表中該元素
= D + A + B + O
= [D,A,B,O]

mro(E) = E + merge(mro(C),mro(D),[C,D])    
= E + merge([C,B,O],[D,A,B,O],[C,D])        #merge中的第一個佇列的第一個元素C是後面的元素的第一個元素,所以可以取出,並刪除所有列表中該元素
= E + C + merge([B,O],[D,A,B,O],[D])        #merge中的第一個佇列的第一個元素B不是佇列的第一個元素,且存在於其他佇列,所以取第二個列表的第一個元素D,D滿足要求,所以可以取出,並刪除所有列表中該元素
= E + C + D + merge([B,O],[A,B,O])          #merge中的第一個佇列的第一個元素B不是佇列的第一個元素,且存在於其他佇列,所以取第二個列表的第一個元素A,A滿足要求,所以可以取出,並刪除所有列表中該元素
= E + C + D + A + merge([B,O],[B,O])        #merge中的第一個佇列的第一個元素B是後面的元素的第一個元素,所以可以取出,並刪除所有列表中該元素
= E + C + D + A + B + merge([O],[O])        ##O是後面的元素的第一個元素,所以取出,並刪除所有列表中該元素
= E + C + D + A + B + O
= [E,C,D,A,B,O]
這個算起來挺麻煩,所以類的繼承還是不要寫的那麼複雜了,維護起來也很麻煩的。


經典類和新式類例項

經典類

class A():
    ret = 1
    def __init__(self):
        pass
           
class B(A):
    def __init__(self):
        pass
   
class C(A):
    ret = 2
    def __init__(self):
        pass
           
class D(B, C):
    def __init__(self):
        pass

#B->A->C         
x = D()
print x.ret
輸出為:1

新式類

class A(object):
    ret = 1
    def __init__(self):
        pass
          
class B(A):
    def __init__(self):
        pass
  
class C(A):
    ret = 2
    def __init__(self):
        pass
          
class D(B, C):
    def __init__(self):
        pass
    
#B->C->A       
x = D()
print x.ret
輸出為:2

super()

super(self,C).func()    #呼叫的並不是其父類C的func,而是C在MRO中的下一個類的func,不能再經典類中使用

開始一直以為在多重繼承的情況下選擇執行某個父類的方法,網上有不少也是這麼說的(被誤導了)。

class A(object):
    def __init__(self):
        print "A"
         
class B(object):
    def __init__(self):
        print "B"
          
class C(object):
    def __init__(self):
        print "C"
  
class D(A,B,C):
    def __init__(self):
        super(D,self).__init__()
        super(A,self).__init__()
        super(B,self).__init__()
        super(C,self).__init__()
         
X  = D()

會發現:

super(D,self).__init__()

執行的是A.__init__()

super(A,self).__init__()
執行的是B.__init__()
super(B,self).__init__()

執行的是C.__init__()

super(C,self).__init__()
執行的是Object.__init__()

這是因為mro(D)為:[ D, A, B, C, Object]