1. 程式人生 > >python中的多繼承(經典類和新式類)

python中的多繼承(經典類和新式類)

python和C++一樣,支援多繼承。概念雖然容易,但是困難的工作是如果子類呼叫一個自身沒有定義的屬性,它是按照何種順序去到父類尋找呢,尤其是眾多父類中有多個都包含該同名屬性。

  1. class P1 #(object): 
  2.    def foo(self):           
  3.        print 'p1-foo' 
  4. class P2 #(object): 
  5.    def foo(self): 
  6.        print 'p2-foo' 
  7.    def bar(self): 
  8.        print 'p2-bar' 
  9. class C1 (P1,P2): 
  10.    pass  
  11. class C2 (P1,P2): 
  12.    def bar(self): 
  13.        print 'C2-bar'   
  14. class D(C1,C2): 
  15.    pass 

對經典類和新式類來說,屬性的查詢順序是不同的。現在我們分別看一下經典類和新式類兩種不同的表現

1、經典類

  1. d=D() 
  2. d.foo() # 輸出 p1-foo 
  3. d.bar() # 輸出 p2-bar 

例項d呼叫foo()時,搜尋順序是 D => C1 => P1

例項d呼叫bar()時,搜尋順序是 D => C1 => P1 => P2

換句話說,經典類的搜尋方式是按照“從左至右,深度優先”的方式去查詢屬性。d先查詢自身是否有foo方法,沒有則查詢最近的父類C1裡是否有該方法,如果沒有則繼續向上查詢,直到在P1中找到該方法,查詢結束。

2、新式類

使用新式類要去掉第一段程式碼中的註釋

  1. d=D() 
  2. d.foo() # 輸出 p1-foo 
  3. d.bar() # 輸出 c2-bar 

例項d呼叫foo()時,搜尋順序是 D => C1 => C2 => P1

例項d呼叫bar()時,搜尋順序是 D => C1 => C2

可以看出,新式類的搜尋方式是採用“廣度優先”的方式去查詢屬性。

在python3中類已經新增(object)



出處:https://www.cnblogs.com/linyawen/archive/2012/04/25/2469538.html

補充:

從Python2.2開始,Python 引入了 new style class(新式類)

新式類跟經典類的差別主要是以下幾點:

  1. 新式類物件可以直接通過__class__屬性獲取自身型別:type

  1. # -*- coding:utf-8 -*-  
  2. class E:    
  3. #經典類
  4.     pass
  5. class E1(object):    
  6. #新式類
  7.     pass
  8. e = E()  
  9. print"經典類"
  10. print e  
  11. print type(e)  
  12. print e.__class__  
  13. print"新式類"
  14. e1 = E1()  
  15. print e1  
  16. print e1.__class__  
  17. print type(e1)  
  1. 經典類  
  2. <__main__.E instance at 0x0000000002250B08>  
  3. <type 'instance'>  
  4. __main__.E  
  5. 新式類  
  6. <__main__.E1 object at 0x0000000002248710>  
  7. <class'__main__.E1'>  
  8. <class'__main__.E1'>  

我使用的是python 2.7。

E1是定義的新式類。那麼輸輸出e1的時候,不論是type(e1),還是e1.__class__都是輸出的<class '__main__.E1'>。

2. 繼承搜尋的順序發生了改變,經典類多繼承屬性搜尋順序: 先深入繼承樹左側,再返回,開始找右側;新式類多繼承屬性搜尋順序: 先水平搜尋,然後再向上移動

  1. # -*- coding:utf-8 -*-  
  2. class A(object):    
  3.     """ 
  4.     新式類 
  5.     作為所有類的基類 
  6.     """
  7.     def foo(self):    
  8.         print"class A"
  9. class A1():    
  10.     """ 
  11.     經典類 
  12.     作為所有類的基類 
  13.     """
  14.     def foo(self):    
  15.         print"class A1"
  16. class C(A):    
  17.     pass
  18. class C1(A1):    
  19.     pass
  20. class D(A):    
  21.     def foo(self):    
  22.         print"class D"
  23. class D1(A1):    
  24.     def foo(self):    
  25.         print"class D1"
  26. class E(C, D):    
  27.     pass
  28. class E1(C1, D1):    
  29.     pass
  30. e = E()  
  31. e.foo()  
  32. e1 = E1()  
  33. e1.foo()  

輸出

  1. class D  
  2. class A1  

因為A新式類,對於繼承A類都是新式類,首先要查詢類E中是否有foo(),如果沒有則按順序查詢C->D->A。它是一種廣度優先查詢方式。

經典類

因為A1經典類,對於繼承A1類都是經典類,首先要查詢類E1中是否有foo(),如果沒有則按順序查詢C1->A1->D1。它是一種深度優先查詢方式。

經典類

3. 新式類增加了__slots__內建屬性, 可以把例項屬性的種類鎖定到__slots__規定的範圍之中。

比如只允許對A例項新增name和age屬性:

  1. # -*- coding:utf-8 -*-  
  2. class A(object):    
  3.     __slots__ = ('name''age')   
  4. class A1():    
  5.     __slots__ = ('name''age')   
  6. a1 = A1()  
  7. a = A()  
  8. a1.name1 = "a1"
  9. a.name1 = "a"

A是新式類添加了__slots__ 屬性,所以只允許新增 name age

A1經典類__slots__ 屬性沒用,

  1. Traceback (most recent call last):  
  2.   File "t.py", line 13in <module>  
  3.     a.name1 = "a"
  4. AttributeError: 'A' object has no attribute 'name1'

所以a.name是會出錯的

通常每一個例項都會有一個__dict__屬性,用來記錄例項中所有的屬性和方法,也是通過這個字典,可以讓例項繫結任意的屬性

而__slots__屬性作用就是,當類C有比較少的變數,而且擁有__slots__屬性時,

類C的例項 就沒有__dict__屬性,而是把變數的值存在一個固定的地方。如果試圖訪問一個__slots__中沒有

的屬性,例項就會報錯。這樣操作有什麼好處呢?__slots__屬性雖然令例項失去了繫結任意屬性的便利,

但是因為每一個例項沒有__dict__屬性,卻能有效節省每一個例項的記憶體消耗,有利於生成小而精

乾的例項。

4. 新式類增加了__getattribute__方法

  1. class A(object):    
  2.     def __getattribute__(self, *args, **kwargs):    
  3.         print"A.__getattribute__"
  4. class A1():    
  5.     def __getattribute__(self, *args, **kwargs):    
  6.         print"A1.__getattribute__"
  7. a1 = A1()  
  8. a = A()  
  9. a.test  
  10. print"========="
  11. a1.test  
  1. A.__getattribute__  
  2. =========  
  3. Traceback (most recent call last):  
  4.   File "t.py", line 18in <module>  
  5.     a1.test  
  6. AttributeError: A1 instance has no attribute 'test'

可以看出A是新式類,每次通過例項訪問屬性,都會經過__getattribute__函式,

A1不會呼叫__getattribute__所以出錯了

Python 2.x中預設都是經典類,只有顯式繼承了object才是新式類

Python 3.x中預設都是新式類,不必顯式的繼承object

出處:https://blog.csdn.net/u010066807/article/details/46896835