1. 程式人生 > >Python基礎----繼承派生、組合、接口和抽象類

Python基礎----繼承派生、組合、接口和抽象類

子類 tool study href 組合 name anim walk 年齡

類的繼承與派生

經典類和新式類

在python3中,所有類默認繼承object,但凡是繼承了object類的子類,以及該子類的子類,都稱為新式類(在python3中所有的類都是新式類)

沒有繼承object類的子類成為經典類(在python2中,沒有繼承object的類,以及它的子類,都是經典類)

技術分享
1 class People:
2     pass
3 class Animal:
4     pass
5 class Student(People,Animal): #People、Animal稱為基類或父類,Student為子類,Student繼承了People和Animal的所有屬性
6     pass
7 print(Student.__bases__)    #__bases__方法,查看繼承的類的元組
8 print(People.__bases__)
9 print(Animal.__bases__)
技術分享

輸出結果:

1 (<class ‘__main__.People‘>, <class ‘__main__.Animal‘>)    #繼承了兩個父類
2 (<class ‘object‘>,)    #默認繼承了object類
3 (<class ‘object‘>,)

繼承

繼承是為了減少代碼重用的問題,以減少代碼冗余。

繼承是一種是什麽是什麽的關系,例如老師類是人類,而非老師類是生日類

繼承類示例:

技術分享
 1 class People:    #定義父類People
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5     def walk(self):
 6         print(‘%s is walking‘ %self.name)
 7 
 8 #Teacher類和Student類無任何屬性
 9 class Teacher(People):    #Teacher類繼承People類的屬性
10     pass
11 class Student(People):    #Student類繼承People類的屬性
12     pass
技術分享

引用測試:

技術分享
 1 t=Teacher(‘bob‘,18)    #實例化一個Teacher對象,而非People對象,Student子類同理
 2 print(type(t)) 
 3 print(t.name,t.age)
 4 print(t.__dict__)
 5 t.walk()    #Teacher子類繼承了People的屬性,使得Teacher子類的對象能夠調用到父類的屬性
 6 
 7 輸出結果:
 8 <class ‘__main__.Teacher‘>
 9 bob 18
10 {‘name‘: ‘bob‘, ‘age‘: 18}
11 bob is walking
技術分享

派生

派生是在子類繼承父類的基礎上, 定義子類獨有的屬性,例如Teacher可以有教師等級的劃分、有教學課程的劃分,但是繼承父類People類是沒有等級和課程的劃分的。

示例:

技術分享
 1 #定義父類People
 2 class People:
 3     def __init__(self, name, age,sex):
 4         self.name = name
 5         self.age = age
 6         self.sex=sex
 7     def walk(self):
 8         print(‘%s is walking‘ % self.name)
 9     def test(self):
10         print(‘test class from father class %s‘ %self.name)
11 #定義Teacher子類
12 class Teacher(People):
13     school = ‘jialidun‘
14     def __init__(self, name, age,sex,level,salary):
15         People.__init__(self,name,age,sex)    #繼承父類的初始化內容,實例化時候接收的參數name、age、sex會傳給People.__init__
16         self.level=level    #派生的獨有屬性
17         self.salary=salary    #派生的獨有屬性
18     def teach(self):    #派生的獨有屬性
19         print(‘%s is teaching‘ %self.name)
20     def test(self):    #派生父類的已有屬性,對象在進行屬性引用的時候會優先引用實例化過程中用到的類
21         People.test(self)
22         print(‘from teacher‘)
23 #定義Student子類
24 class Student(People):
25     def __init__(self, name, age,sex,group):
26         People.__init__(self, name, age, sex)
27         self.group=group
28     def study(self):
29             print(‘%s is studying‘ %self.name)
技術分享

測試驗證:

1 t=Teacher(‘natasha‘,18,‘male‘,10,3000) #__init__(t,‘natasha‘,18,‘male‘,10,3000)
2 print(Teacher.__bases__)
3 print(Teacher.__dict__)
4 t.test()

組合

不同於繼承,組合是包含的意思,表示一種什麽有什麽的關系,也是為了減少重復代碼的

示例:還是People、Teacher和Student的例子,只是加上了一個Birthday生日類

技術分享
 1 #Birthday類,需要傳入年月日
 2 class Birthday:
 3     def __init__(self,year,mon,day):
 4         self.year=year
 5         self.mon=mon
 6         self.day=day
 7     def tell_birth(self):
 8         print(‘出生於<%s>年 <%s>月 <%s>日‘ % (self.year,self.mon,self.day))
 9 #People類,需要接受名字年齡年月日,年月日傳給Birthday類
10 class People:
11     def __init__(self, name, age, year, mon, day):
12         self.name = name
13         self.age = age
14         #__init__接收的year, mon, day傳給Birthday類
15         self.birth = Birthday(year, mon, day)   #包含Birthday類,生日不只是人類才有,其他動物也可以有生日,不同於繼承
16     def walk(self):
17         print(‘%s is walking‘ % self.name)
18 #Teacher類
19 class Teacher(People):
20     def __init__(self, name, age, year, mon, day,level,salary):
21         #__init__接收的name, age, year, mon, day傳給People類
22         People.__init__(self,name,age,year,mon,day)
23         self.level=level
24         self.salary=salary
25     def teach(self):
26         print(‘%s is teaching‘ %self.name)
27 #Student類
28 class Student(People):
29     def __init__(self, name, age, year, mon, day,group):
30         People.__init__(self,name,age,year,mon,day)
31         self.group=group
32     def study(self):
33         print(‘%s is studying‘ %self.name)
技術分享

測試驗證:

技術分享
1 t=Teacher(‘hurry‘,18,1990,2,33,10,3000)    #傳入的值為Teacher類接收的值
2 print(t.name,t.age)    #對象t的名字和年齡
3 print(t.birth)    #輸出的是一個類對象,因為父類People定義的birth屬性就是一個類Birthday
4 t.birth.tell_birth()    #查看對象t所繼承的People類的birth屬性(Birthday類)的tell_birth()屬性
5 print(t.birth.year)
6 print(t.birth.mon)
7 print(t.birth.day)
技術分享

接口和抽象類

接口

接口是一組功能的入口,要調用某一組功能,需要通過接口來進行調用,而不需要關註這組功能是如何實現的,要的只是結果。

在類裏,接口是提取了一群類共同的函數,可以把接口當做一個函數的集合。

python模仿接口示例:

技術分享
 1 #模仿Linux內文件讀寫的接口,Linux不管是文本,還是磁盤還是進程都是通過文件去實現的,只不過方法不同,但是沒關系
 2 class File:    #定義一個接口類,提供read和write方法,但是一定是pass沒有處理過程的,因為功能的實現具體靠的是子類
 3     def read(self): #定接口函數read
 4         pass
 5     def write(self): #定義接口函數write
 6         pass
 7 #定義子類實現讀寫功能
 8 #文本文件的讀寫
 9 class Txt(File): #文本,具體實現read和write
10     def du(self):     #註意並不是read
11         print(‘文本數據的讀取方法‘)
12     def xie(self):    #註意並不是write
13         print(‘文本數據的寫入方法‘)
14 #硬盤數據的讀寫
15 class Sata(File): #磁盤,具體實現read和write
16     def read(self):
17         print(‘硬盤數據的讀取方法‘)
18     def write(self):
19         print(‘硬盤數據的寫入方法‘)
20 #進程數據的讀寫
21 class Process(File):
22     def read(self):
23         print(‘進程數據的讀取方法‘)
24     def write(self):
25         print(‘進程數據的寫入方法‘)
技術分享

測試驗證:硬盤和進程一樣,所以制作文本和硬盤的測試即可

硬盤讀寫測試:

技術分享
1 disk=Sata()    #實例化一個硬盤讀寫對象
2 disk.read()    #硬盤讀
3 disk.write()    #硬盤寫
4 
5 輸出結果:
6 硬盤數據的讀取方法
7 硬盤數據的寫入方法
技術分享

文本讀寫測試:執行後會發現沒有任何輸出,那是因為txt對象實際上訪問的read和write屬性並非子類Txt所提供的屬性,Txt所提供的屬性只是du和xie,但是txt對象有read和write屬性,別忘了Txt類是繼承了父類File的屬性,所以實際上txt對象的read和write屬性是父類File提供的

1 txt=Txt()
2 txt.read()
3 txt.write()

正確的做法是將Txt類的du和xie方法改成read和write方法,這麽做的意義為歸一化

歸一化,讓使用者無需關心對象的類是什麽,只需要的知道這些對象都具備某些功能就可以了,這極大地降低了使用者的使用難度。

抽象類

抽象類的本質上也是類,但是抽象類只能夠被繼承,不能進行實例化,也就是說可以當父類,但是不能生成對象。

抽象類介於接口和歸一化中間,用於實現接口的歸一化

當子類繼承抽象類的時候,如果抽象類定義了抽象方法,那麽子類必須要定義同名的方法。即父類限制:

  1、子類必須要有父類的方法

  2、子類實現的方法必須跟父類的方法的名字一樣

python的抽象類通過abc模塊實現。

接口歸一化示例:

技術分享
 1 import abc
 2 class File(metaclass=abc.ABCMeta):  #metaclass指的是元類,邊會講,現在只需記住這個詞
 3     @abc.abstractmethod     #抽象方法,即一個裝飾器裝飾read屬性
 4     def read(self):
 5         pass
 6     @abc.abstractmethod      #抽象方法,即一個裝飾器裝飾write屬性
 7     def write(self):
 8         pass
 9 # # 當繼承File類時候,如果沒有read和write方法,會提示出錯TypeError: Can‘t instantiate abstract class Txt with abstract methods read, write
10 # class Txt(File):
11 #     def du(self):
12 #         print(‘文本數據的讀取方法‘)
13 #     def xie(self):
14 #         print(‘文本數據的寫入方法‘)
15 #定義子類具體實現文本的讀寫操作
16 class Txt(File):
17     def read(self):
18         print(‘文本數據的讀取方法‘)
19     def write(self):
20         print(‘文本數據的寫入方法‘)
21 #定義子類具體實現硬盤的讀寫操作
22 class Sata(File):
23     def read(self):
24         print(‘硬盤數據的讀取方法‘)
25     def write(self):
26         print(‘硬盤數據的寫入方法‘)
27 #定義子類具體實現進程的讀寫操作
28 class Process(File):
29     def read(self):
30         print(‘進程數據的讀取方法‘)
31     def write(self):
32         print(‘進程數據的寫入方法‘)
技術分享

測試驗證:

技術分享
 1 t=Txt()
 2 t.read()
 3 t.write()
 4 s=Sata()
 5 s.read()
 6 s.write()
 7 輸出結果:
 8 文本數據的讀取方法
 9 文本數據的寫入方法
10 硬盤數據的讀取方法
11 硬盤數據的寫入方法
技術分享

Python基礎----繼承派生、組合、接口和抽象類