4月12日 python學習總結 繼承和派生
一、繼承
- 什麽是繼承:
繼承是一種新建類的方式,在python中支持一個子類繼承多個父類
新建類稱為子類或派生類
父類可以稱之為基類或者超類
子類會遺傳父類的屬性
2. 為什麽繼承
減少代碼冗余
3. 定義方式:
class Parent: pass class SubClass(Parent): pass print(SubClass.__bases__) #查看類的父類
4. 繼承,調用父類方法以及self
class Foo: def f1(self):print(‘Foo.f1‘) def f2(self): #self=obj print(‘Foo.f2‘) self.f1() #obj.f1() class Bar(Foo): def f1(self): print(‘Bar.f1‘) obj=Bar() # print(obj.__dict__) obj.f2() #輸出為: FOO.f1 # Bar.f1
二、 派生
子類定義自己新的屬性,如果與父類同名,以子類自己的為準
在子類派生出的新方法中重用父類功能(最好不要兩種方法混著用):
- 指名道姓的調用(與繼承沒什麽關系)
class OldboyPeople: school = ‘oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(""" ===========個人信息========== 姓名:%s 年齡:%s 性別:%s""" %(self.name,self.age,self.sex)) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary): # self.name = name # self.age = age # self.sex = sex OldboyPeople.__init__(self,name, age, sex) #此處直接調用父類方法 self.level = level self.salary = salary def tell_info(self): OldboyPeople.tell_info(self) print(""" 等級:%s 薪資:%s """ %(self.level,self.salary))
2. super()調用(嚴格依賴於繼承)
super()的返回值是一個特殊的對象,該對象專門用來調用父類中的屬性
class OldboyTeacher(OldboyPeople): # tea1,‘egon‘, 18, ‘male‘, 9, 3.1 def __init__(self, name, age, sex, level, salary): OldboyPeople.__init__(self,name, age, sex) #調用父類方法 # super(OldboyTeacher,self).__init__(name,age,sex) 在python2中調用時用這種寫法 self.level = level self.salary = salary def tell_info(self): # OldboyPeople.tell_info(self) super().tell_info() print(""" 等級:%s 薪資:%s """ %(self.level,self.salary))
super()嚴格依賴繼承
三、新式類與經典類
1、新式類:
繼承object的類,以及該類的子類,都是新式類
在python3中,如果一個類沒有指定繼承的父類,默認就繼承object
所以說python3中所有的類都是新式類
2、經典類 (只有在python2才區分經典類與新式類):
沒有繼承object的類,以及該類的子類,都是經典類
區別: 在菱形繼承的背景下,經典類和新式類才有區別。非菱形繼承時,是一樣的。但是當菱形繼承時,新式類會采用廣度優先,經典類深度優先
深度優先:按照從左往右的順序,每一條分支走到底,再轉入下一條分支
廣度優先:按照從左往右的順序,忽略菱形最頂上的父類,將除該父類之外的所有類進行深度優先遍歷,最後再查找該父類
多繼承的類便利順序:一個對象繼承多個類,按照定義順序,從左到右,深度便利
經典類遍歷結果:ABEGCFD
新式類便利結果:ABECFDG
#coding:utf-8 #在菱形繼承的背景下,查找屬性 #1、經典類:深度優先 #2、新式類:廣度優先 class A: # def test(self): # print(‘from A‘) pass class B(A): # def test(self): # print(‘from B‘) pass class C(A): # def test(self): # print(‘from C‘) pass class D(B): # def test(self): # print(‘from D‘) pass class E(C): # def test(self): # print(‘from E‘) pass class F(D,E): # def test(self): # print(‘from F‘) pass # f1=F() # f1.test() print(F.mro()) # F->D->B->E->C-A->object
super()嚴格依賴繼承
#super()會嚴格按照mro列表從當前查找到的位置繼續往後查找 class A: def test(self): print(‘A.test‘) super().f1() class B: def f1(self): print(‘from B‘) class C(A,B): pass c=C() print(C.mro()) #C->A->B->object c.test()
作 業 :
4月12日作業 1、類的屬性和對象的屬性有什麽區別? 類的屬性是所有對象共享的,對象的屬性,是對象單獨使用的 2、面向過程編程與面向對象編程的區別與應用場景? 1、面向過程是流水線式編程,先做什麽在做什麽 2、面向對象是上帝視角的,面向一個個對象,讓對象之間交互解決問題 3、類和對象在內存中是如何保存的。 都是一串數據 類在定義時,執行代碼,開辟內存空間,存放各種屬性名和方法名,但不執行__init__方法 對象在執行是,調用類的__init__方法,開辟內存空間,存放該對象自己獨有的屬性名 4、什麽是綁定到對象的方法,、如何定義,如何調用,給誰用?有什麽特性 類的方法 類的方法是綁定給對象用的,一個類的每一個對象,對應相同的類方法,在調用時相互獨立,互不相幹 5、如下示例, 請用面向對象的形式優化以下代碼 在沒有學習類這個概念時,數據與功能是分離的,如下 def exc1(host,port,db,charset): conn=connect(host,port,db,charset) conn.execute(sql) return xxx def exc2(host,port,db,charset,proc_name) conn=connect(host,port,db,charset) conn.call_proc(sql) return xxx # 每次調用都需要重復傳入一堆參數 exc1(‘127.0.0.1‘,3306,‘db1‘,‘utf8‘,‘select * from tb1;‘) exc2(‘127.0.0.1‘,3306,‘db1‘,‘utf8‘,‘存儲過程的名字‘) class exc: def __int__(self,host,port,db,charset,proc_name): self.host=host self.port=port self.db=db self.charset=charset self.proc_name = proc_name def exc1(self): conn = connect(self.host, self.port, self.db, self.charset) conn.execute(sql) return xxx def exc2(self): conn = connect(self.host, self.port, self.db, self.charset) conn.call_proc(sql) return xxx 6、下面這段代碼的輸出結果將是什麽?請解釋。 class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x, Child1.x, Child2.x) # 1 1 1 Child1.x = 2 print(Parent.x, Child1.x, Child2.x) # 1 2 1 Parent.x = 3 print(Parent.x, Child1.x, Child2.x) # 3 2 3 7、多重繼承的執行順序,請解答以下輸出結果是什麽?並解釋。 class A(object): def __init__(self): print(‘A‘) super(A, self).__init__() class B(object): def __init__(self): print(‘B‘) super(B, self).__init__() class C(A): def __init__(self): print(‘C‘) super(C, self).__init__() class D(A): def __init__(self): print(‘D‘) super(D, self).__init__() class E(B, C): def __init__(self): print(‘E‘) super(E, self).__init__() class F(C, B, D): def __init__(self): print(‘F‘) super(F, self).__init__() class G(D, B): def __init__(self): print(‘G‘) super(G, self).__init__() if __name__ == ‘__main__‘: g = G() # G D A B f = F() # F C B D A 8、什麽是新式類,什麽是經典類,二者有什麽區別?什麽是深度優先,什麽是廣度優先? 新式類:繼承自object,其子類也是新式類 經典類:沒有繼承自object的所有類,其子類也是經典類 區別: 非菱形繼承時,是一樣的。但是當菱形繼承時,新式類會采用廣度優先,經典類深度優先 深度優先:按照從左往右的順序,每一條分支走到底,再轉入下一條分支 廣度優先:按照從左往右的順序,忽略菱形最頂上的父類,將除該父類之外的所有類進行深度優先遍歷,最後再查找該父類 9、用面向對象的形式編寫一個老師類, 老師有特征:編號、姓名、性別、年齡、等級、工資,老師類中有功能 1、生成老師唯一編號的功能,可以用hashlib對當前時間加上老師的所有信息進行校驗得到一個hash值來作為老師的編號 def create_id(self): pass 2、獲取老師所有信息 def tell_info(self): pass 3、將老師對象序列化保存到文件裏,文件名即老師的編號,提示功能如下 def save(self): with open(‘老師的編號‘,‘wb‘) as f: pickle.dump(self,f) 4、從文件夾中取出存儲老師對象的文件,然後反序列化出老師對象,提示功能如下 def get_obj_by_id(self,id): return pickle.load(open(id,‘rb‘)) 答案: import hashlib import datetime import pickle class Teacher: def create_id(self): m=hashlib.md5() m.update(self.name.encode(‘gbk‘)) m.update(self.sex.encode(‘gbk‘)) m.update(bytes(self.age)) m.update(bytes(self.level)) m.update(bytes(self.salary)) m.update(str(datetime.datetime.now()).encode(‘gbk‘)) return m.hexdigest() def __init__(self,name,sex,age,level,salary): self.name=name self.age=age self.sex=sex self.level=level self.salary=salary self.id=self.create_id() def tell_info(self): print(self.__dict__) def save(self): with open(r‘%s.json‘%self.id, ‘wb‘) as f: pickle.dump(self, f) def get_obj_by_id(self): with open(r‘%s.json‘ % self.id, ‘rb‘) as f: info= pickle.load(f).__dict__ return info t=Teacher(‘egon‘,‘male‘,18,9,1.3) print(t.__dict__) t.save() print(t.get_obj_by_id()) 10、按照定義老師的方式,再定義一個學生類 import hashlib import datetime import pickle class Student: def create_id(self): m=hashlib.md5() m.update(self.name.encode(‘gbk‘)) m.update(self.sex.encode(‘gbk‘)) m.update(bytes(self.age)) m.update(str(datetime.datetime.now()).encode(‘gbk‘)) return m.hexdigest() def __init__(self,name,sex,age): self.name=name self.age=age self.sex=sex self.id=self.create_id() def tell_info(self): print(self.__dict__) def save(self): with open(r‘%s.json‘%self.id, ‘wb‘) as f: pickle.dump(self, f) def get_obj_by_id(self): with open(r‘%s.json‘ % self.id, ‘rb‘) as f: info= pickle.load(f).__dict__ return info s=Student(‘egon‘,‘male‘,18) print(s.__dict__) s.save() print(s.get_obj_by_id()) 11、抽象老師類與學生類得到父類,用繼承的方式減少代碼冗余 import hashlib import datetime import pickle class ParentClass: def create_id(self): m=hashlib.md5() m.update(self.name.encode(‘gbk‘)) m.update(self.sex.encode(‘gbk‘)) m.update(bytes(self.age)) m.update(str(datetime.datetime.now()).encode(‘gbk‘)) return m.hexdigest() def __init__(self,name,sex,age): self.name=name self.age=age self.sex=sex self.id=self.create_id() def tell_info(self): print(self.__dict__) def save(self): with open(r‘%s.json‘%self.id, ‘wb‘) as f: pickle.dump(self, f) def get_obj_by_id(self): with open(r‘%s.json‘ % self.id, ‘rb‘) as f: info= pickle.load(f).__dict__ return info class Teacher(ParentClass): def create_id(self): m = hashlib.md5() m.update(self.name.encode(‘gbk‘)) m.update(self.sex.encode(‘gbk‘)) m.update(bytes(self.age)) m.update(bytes(self.level)) m.update(bytes(self.salary)) m.update(str(datetime.datetime.now()).encode(‘gbk‘)) return m.hexdigest() def __init__(self, name, sex, age, level, salary): self.level = level self.salary = salary super().__init__(name, sex, age) self.id = self.create_id() class Student(ParentClass): def learn(self): print(‘learning...‘) 12、基於面向對象設計一個對戰遊戲並使用繼承優化代碼,參考博客 http://www.cnblogs.com/linhaifeng/articles/7340497.html#_label1
4月12日 python學習總結 繼承和派生