?
創(chuàng)新互聯(lián)基于分布式IDC數(shù)據(jù)中心構(gòu)建的平臺(tái)為眾多戶提供雅安電信機(jī)房 四川大帶寬租用 成都機(jī)柜租用 成都服務(wù)器租用。
目錄
inheritance繼承:...1
繼承中的訪問(wèn)控制:...5
繼承中的初始化:...9
多繼承:...13
mixin:...16
習(xí)題:...23
single linkedlist.25
double linkedlist:...28
習(xí)題:...32
?
?
?
人類和豬類都繼承自動(dòng)物類;
個(gè)體繼承自父母,繼承了父母的一部分特征,但也可以有自己的個(gè)性;
在面向?qū)ο蟮氖澜缰校瑥母割惱^承,就可直接擁有父類的屬性和方法,這樣可減少代碼、多復(fù)用;
子類可定義自己的屬性和方法;
?
子類繼承父類的特征,特征即類屬性、類方法、靜態(tài)方法、實(shí)例屬性;
公共的屬性和方法,包括_開頭的;
隱私屬性和方法是__開頭的,對(duì)外暴露提供的方法要為屬性裝飾器的方法;
?
open-close-principle開閉原則:
對(duì)擴(kuò)展開放(繼承開放),擴(kuò)展個(gè)性化的地方;
修改關(guān)閉;
?
繼承也稱派生;
class Cat(Animal)這種形式就是從父類繼承,括號(hào)中寫繼承的類的列表;
繼承可讓子類從父類獲取特征(屬性和方法);
父類,Animal就是Cat的父類,也稱基類、超類;
子類,Cat就是Animal的子類,也稱派生類;
?
定義:
class 子類(基類1[,基類2,...]):
???????? 語(yǔ)句塊
如果定義類時(shí),沒(méi)有基類列表,等同于繼承自object,在python3中,object是所有對(duì)象的根基類,倒置的根;
python2中有古典類(舊式類)、新式類,3.0全是新式類;
python支持多繼承,繼承也可以多級(jí),多級(jí)展開即tree,不一定是二叉樹;
單繼承(一條鏈串起來(lái));多繼承;
?
單繼承關(guān)系圖:
子類指向父類;
?
繼承的特殊屬性和方法:
__base__,類的基類,過(guò)時(shí)了;
__bases__,類的基類元組;
__mro__,多繼承時(shí)用,顯示方法查找順序,基類的元組,多繼承中非常重要,mro()方法的結(jié)果會(huì)放在__mro__里;
mro(),多繼承時(shí)用,同上,int.mro(),在類上用該方法,實(shí)例上不能用;
__subclasses__(),類的子類列表,int.__subclasses__();
?
python不同版本的類:
py2.2之前,類是沒(méi)有共同的祖先的,之后,引入object類,它是所有類的共同祖先類object;
py2為了兼容,分為古典類(舊式類)和新式類;
py3中全是新式類;
新式類都是繼承自object類的,新式類可使用super();
py2與py3版本不同,不僅是語(yǔ)法方面,還有類構(gòu)建方面;
?
例:
class Animal(object):?? #等價(jià)于class Animal:,默認(rèn)繼承自object,若加上object則兼容python2
??? x = 123
??? def __init__(self):
??????? self.name = 'tom'
?
??? def getname(self):
??????? return self.name
?
class Cat(Animal):
??? pass
?
class Dog():
??? pass
?
tom = Cat()
print(tom.name)
print(tom.__dict__)
print(tom.getname())
?
dog = Dog()
# print(dog.name)
# print(dog.getname())
輸出:
tom
{'name': 'tom'}
tom
?
例:
class Animal(object):
??? x = 123
??? def __init__(self,name):
??????? self._name = name
?
??? @property?? #裝飾后的也能繼承,終歸Animal類的管轄
??? def name(self):
??????? return self._name?? #公共屬性
?
??? def shout(self):
??????? print('Animal shout')
?
class Cat(Animal):
??? x = 'cat'?? #override覆蓋
??? def shout(self):?? #override覆蓋(重寫),與rewrite是兩碼事
??????? print('miao')
?
class Dog(Animal):
??? pass
?
class Garfield(Cat):
??? pass
?
class PersiaCat(Cat):
??? # def __init__(self):?? #call to __init__ of super class is missed,需調(diào)用父類方法
??? #???? self.eyes = 'blue'
??? pass
?
tom = Cat('tom')
print(tom.name)
print(tom.__dict__)
tom.shout()?? #自有的,體現(xiàn)個(gè)性
?
dog = Dog('ahuang')
dog.shout()?? #自己沒(méi)有的,用繼承的'Animal shout'
?
gf = Garfield(Cat)
gf.shout()
?
pc = PersiaCat('persiacat')
print(pc.__dict__)
# pc.name = 'persiacat'?? #不可修改
pc.eyes = 'blue,green'
pc.shout()
print(pc.name,pc.eyes)
print(pc.__dict__)
輸出:
tom
{'_name': 'tom'}
miao
Animal shout
miao
{'_name': 'persiacat'}
miao
persiacat blue,green
{'_name': 'persiacat', 'eyes': 'blue,green'}
?
例:
gf = Garfield(Cat)
gf.shout()
print('gf.mro={}'.format(gf.__class__.mro()))?? #mro()方法,只能在類上用,不能在實(shí)例上用
print('gf.mro={}'.format(gf.__class__.__mro__))
print('gf.bases={}'.format(gf.__class__.__bases__))
輸出:
miao
gf.mro=[
gf.mro=(
gf.bases=(
?
例:
In [1]: int.__subclasses__()
Out[1]: [bool, sre_constants._NamedIntConstant,
In [2]: int.__bases__
Out[2]: (object,)
In [3]: int.__base__
Out[3]: object
In [4]: int.mro()?? #返回int自身
Out[4]: [int, object]
In [5]: int.__mro__
Out[5]: (int, object)
?
?
?
從父類繼承,自己沒(méi)有的,就可到父類中找;
私有的都是不可訪問(wèn)的,本質(zhì)上是改了名并放入所在類的__dict__中,知道這個(gè)新名稱就可直接找到這個(gè)隱藏的變量,這是個(gè)黑魔法技巧,慎用;
?
繼承時(shí),公有的(除__開頭的),子類和實(shí)例都可隨意訪問(wèn);私有的,被隱藏,子類和實(shí)例不可直接訪問(wèn),私有變量所在的類內(nèi)有方法,則可訪問(wèn)這個(gè)私有變量;
python通過(guò)自己一套實(shí)現(xiàn),實(shí)現(xiàn)和其它語(yǔ)言一樣的面向?qū)ο蟮睦^承機(jī)制;
?
屬性查找順序:
實(shí)例的__dict__-->類__dict__,有繼承-->父類__dict__;
如果搜索這些地方后沒(méi)找到就拋異常,先找到就立即返回了;
?
方法的重寫(覆蓋)override:
super(),新式類中提供了該方法,可訪問(wèn)到父類的屬性,具體原理后續(xù);
Animal.__init__(self,name),py2寫法;
super().__init__(name),相當(dāng)于super(Cat,self).__init__(name)完整寫法,py3寫法,
self.__class__.__base__.__init__(self,name),不推薦使用;
?
例:
class Animal(object):
??? x = 123
??? def __init__(self,name):
??????? self._name = name
??????? self.__age = 10
?
class Cat(Animal):
??? x = 'cat'
?
class Garfield(Cat):
??? pass
?
tom = Garfield('tom')
print(tom.__dict__)?? #輸出隱私屬性_Animal__age,_父類的名字__屬性,誰(shuí)有這個(gè)屬性編譯器就改名字為誰(shuí),當(dāng)前只Animal類上有
print(Garfield.__dict__)?? #子類先找自己的實(shí)例,再依次往上找父類
print(Cat.__dict__)?? #類中找不到_Animal__age,該屬性在實(shí)例里,self即為實(shí)例,實(shí)例屬性的__dict__,方法是在類中
輸出:
{'_name': 'tom', '_Animal__age': 10}
{'__module__': '__main__', '__doc__': None}
{'__module__': '__main__', 'x': 'cat', '__doc__': None}
?
例(方法的重寫(覆蓋)):
class Animal(object):
??? x = 123
??? def __init__(self,name):
??????? self._name = name
??????? self.__age = 10
?
??? @property
??? def name(self):
??????? return self._name
?
??? def shout(self):
??????? print('Animal shout')
?
class Cat(Animal):
??? x = 'cat'
??? def __init__(self,name):
??????? # super(Cat,self).__init__(name)
??????? # super().__init__(name)
??????? Animal.__init__(self,name)?? #子類中也初始化,python2寫法;py3寫法為super().__init__(name),新式類推薦使用此種寫法;兩種方式等價(jià);
??????? #self._name = name?? #2個(gè)屬性{'_name': 'tom', '_Animal__age': 10}
?????????????????? #self.catname = name?? #3個(gè)屬性{'_name': 'tom', '_Animal__age': 10, 'catname': 'tom'}
?????????????????? self._name = 'cat' + name?? #2個(gè)屬性{'_name': 'cattom', '_Animal__age': 10}
?
tom = Cat('tom')
print(tom.name)
print(tom.__dict__)
輸出:
#tom
#{'_name': 'tom', '_Animal__age': 10}
#tom
#{'_name': 'tom', '_Animal__age': 10, 'catname': 'tom'}
cattom
{'_name': 'cattom', '_Animal__age': 10}
?
例(方法的重寫(覆蓋)):
class Animal:
??? def shout(self):
??????? print('Animal shout')
?
class Cat(Animal):
??? def shout(self):
??????? print('miao')
?
??? def shout(self):?? #覆蓋了自身的shout,之前的徹底沒(méi)有了;Animal中的shout仍在自己內(nèi)部,在調(diào)用時(shí)遮蓋了;這兩次覆蓋有差異
??????? print('cat shout')
??????? print(super())
??????? print(super(Cat,self))?? #等價(jià)于super()
??????? super().shout()
??????? self.__class__.__base__.shout(self)?? #不推薦使用,等價(jià)于super()
?
cat = Cat()
cat.shout()
輸出:
cat shout
Animal shout
Animal shout
?
例:
class Animal(object):
??? x = 123
??? def __init__(self,name):
??????? self._name = name
??????? self.__age = 10
?
??? @property
??? def name(self):
??????? return self._name
?
??? def shout(self):
??????? print('Animal shout')
?
class Cat(Animal):
??? x = 'cat'
??? def __init__(self,name):
??????? # self._name = name
??????? self._name = 'cat' + name??#先后有影響
??????? Animal.__init__(self, name)
?
tom = Cat('tom')
print(tom.name)
print(tom.__dict__)
輸出:
tom
{'_name': 'tom', '_Animal__age': 10}
?
例:
class Animal:
??? @classmethod
??? def clsmtd(cls):
??????? print(cls,cls.__name__)
?
class Cat(Animal):
??? def __init__(self,name):
??????? self.name = name
??? @classmethod
??? def clsmtd(cls):
??????? print(cls,cls.__name__)
?
class Garfield(Cat): pass
?
tom = Garfield('tom')
tom.clsmtd()?? #多態(tài),多態(tài)前提要繼承,用哪個(gè)類創(chuàng)建的實(shí)例就是哪個(gè)類
?
print(tom.__dict__)
print(Cat.__dict__)
print(Animal.__dict__)?? #公有的(除__開頭),父類的都是你的,py內(nèi)部會(huì)自動(dòng)逐級(jí)找(可理解為繼承的就是我的),傳什么就打印什么,用哪個(gè)類創(chuàng)建的實(shí)例就是哪個(gè)類,雖有父類的特征在都繼承下來(lái)
輸出:
{'name': 'tom'}
{'__module__': '__main__', '__init__':
{'__module__': '__main__', 'clsmtd':
?
?
?
好習(xí)慣 ,在子類中只要有初始化__init__方法,就要把父類的寫上,如super().__init__(name),即如果父類中定義了__init__方法,子類中也有__init__,就該在子類的__init__中調(diào)用它;
?
建議:少在繼承中使用私有變量;
?
例:
class A:
??? def __init__(self,a):
??????? self.a = a
?
class B(A):?? #類B定義時(shí)聲明繼承自類A,則在類B中__bases__中可看到類A,但這和是否調(diào)用類A的構(gòu)造方法是兩回事
??? def __init__(self,b,c):?? #如果B中調(diào)用了A的構(gòu)造方法super().__init__(a)就可擁有父類的屬性了,查看b的__dict__
??????? self.b = b
??????? self.c = c
?
??? def printv(self):
??????? print(self.b)
??????? print(self.c)
??????? # print(self.a)?? #AttributeError: 'B' object has no attribute 'a'
?
b = B(20,30)
b.printv()
print(B.__bases__)
?
print(B.__dict__)
print(A.__dict__)
輸出:
20
30
(
{'__module__': '__main__', '__init__':
{'__module__': '__main__', '__init__':
?
解決上例問(wèn)題:
class A:
??? def __init__(self,a):
??????? self.a = a
?
class B(A):
??? def __init__(self,b,c):
??????? super().__init__(b+c)?? #等價(jià)于A.__init__(self,b+c)
??????? self.b = b
??????? self.c = c
?
??? def printv(self):
??????? print(self.b)
??????? print(self.c)
??????? print(self.a)
?
b = B(20,30)
b.printv()
print(B.__bases__)
?
print(b.__dict__)
print(B.__dict__)
print(A.__dict__)
輸出:
20
30
50
(
{'a': 50, 'b': 20, 'c': 30}
{'__module__': '__main__', '__init__':
{'__module__': '__main__', '__init__':
?
例:
class A:
??? def __init__(self,a,d):
??????? self.a = a
??????? self.__d = d
?
class B(A):
??? def __init__(self,b,c):
??????? super().__init__(b+c,c-b)
??????? self.b = b
??????? self.c = c
??????? self.__d = b + c + 1
?
??? def printv(self):
??????? print(self.b)
??????? print(self.c)
??????? print(self.a)
??????? print(self.__d)
?
b = B(20,30)
b.printv()
print(b.__class__.__bases__)
?
print(b.__dict__)
print(B.__dict__)
print(A.__dict__)
輸出:
20
30
50
51
(
{'a': 50, '_A__d': 10, 'b': 20, 'c': 30, '_B__d': 51}?? #實(shí)例b的__dict__中有的私有屬性,要查看該私有屬性必須在該實(shí)例所在類中有方法,如果該實(shí)例的類中沒(méi)有訪問(wèn)方法,父類中有同樣屬性的訪問(wèn)方法,那最終訪問(wèn)的是父類中的屬性
{'__module__': '__main__', '__init__':
{'__module__': '__main__', '__init__':
?
例:
class Animal:
??? def __init__(self,age):
??????? print('Animal init')
??????? self.__age = age
?
??? def show(self):
??????? print(self.__age)
?
class Cat(Animal):
??? def __init__(self,age,height):
??????? print('Cat init')
??????? super().__init__(age)
??????? self.__age = age + 1
??????? self.__height = height
?
c = Cat(10,20)
c.show()?? #show方法在Animal中定義,__age會(huì)被解釋為_Animal__age,這樣設(shè)計(jì)不好,Cat的實(shí)例應(yīng)顯示自己的屬性值
print(c.__dict__)
print(Cat.__dict__)
print(Animal.__dict__)
輸出:
Cat init
Animal init
10
{'_Animal__age': 10, '_Cat__age': 11, '_Cat__height': 20}
{'__module__': '__main__', '__init__':
{'__module__': '__main__', '__init__':
?
解決上例問(wèn)題:
一個(gè)原則,自己的私有屬性,就該自己的方法讀取和修改,不要借助其它類的方法,即使是父類或派生類的方法;
class Animal:
??? def __init__(self,age):
??????? print('Animal init')
??????? self.__age = age
?
??? def show(self):
??????? print(self.__age)
?
class Cat(Animal):
??? def __init__(self,age,height):
??????? print('Cat init')
??????? super().__init__(age)
??????? self.__age = age + 1
??????? self.__height = height
?
??? def show(self):
??????? print(self.__age)
??????? print(self.__height)
?
c = Cat(10,20)
c.show()
print(c.__dict__)
print(Cat.__dict__)
print(Animal.__dict__)
輸出:
Cat init
Animal init
11
20
{'_Animal__age': 10, '_Cat__age': 11, '_Cat__height': 20}
{'__module__': '__main__', '__init__':
{'__module__': '__main__', '__init__':
?
?
?
ocp原則,open-closed principle,多繼承、少修改;
繼承的用途:增強(qiáng)基類、實(shí)現(xiàn)多態(tài);
?
多態(tài):
在面向?qū)ο笾?,父類、子類通過(guò)繼承聯(lián)系在一起,如果可通過(guò)一套方法,就可實(shí)現(xiàn)不同表現(xiàn),就是多態(tài);
一個(gè)類繼承自多個(gè)類,就是多繼承,它將具有多個(gè)類的特征;
?
多繼承弊端:
多繼承很好的模擬了世界,因?yàn)槭挛锖苌偈菃我焕^承,但是舍棄簡(jiǎn)單,必然引入復(fù)雜性,帶來(lái)了沖突;
如同一個(gè)孩子繼承了來(lái)自父母雙方的特征,那么到底眼睛像爸爸還是媽媽呢?孩子更像誰(shuí)多一點(diǎn)?
多繼承的實(shí)現(xiàn)會(huì)導(dǎo)致編譯器設(shè)計(jì)的復(fù)雜度增加,所以現(xiàn)在很多語(yǔ)言也舍棄了類的多繼承,C++支持多繼承,java舍棄了多繼承;
?
java中,一個(gè)類可實(shí)現(xiàn)多個(gè)接口,一個(gè)接口也可繼承多個(gè)接口,java的接口很純粹,只是方法的聲明,繼承者必須實(shí)現(xiàn)這些方法,就具有了這些能力,就能干什么;
?
多繼承可能會(huì)帶來(lái)二異性,如貓和狗都繼承自動(dòng)物類,如果一個(gè)類多繼承了貓類和狗類,貓和狗都有shout方法,子類空間繼承誰(shuí)的shout呢?
解決方案:
實(shí)現(xiàn)多繼承的語(yǔ)言,可解決二義性,深度優(yōu)先或廣度優(yōu)先;
?
注:?jiǎn)我焕^承;
?
多繼承,分開看兩條均單繼承:
MyClass-->D-->B-->A,深度優(yōu)先;
MyClass-->D-->C-->B-->A,廣度優(yōu)先;
?
多繼承帶來(lái)路徑選擇問(wèn)題,究竟繼承哪個(gè)父類的特征呢?
py使用MRO,method resolution order,解決基類搜索順序問(wèn)題;
歷史原因,MRO有三個(gè)搜索算法:
經(jīng)典算法,按定義從左到右,深度優(yōu)先策略,2.2之前,MyClass->D->B->A->C->A;
新式類算法,經(jīng)典算法的升級(jí),重復(fù)的只保留一個(gè),2.2,MyClass->D->B->C->A->object;
C3算法,在類被創(chuàng)建出來(lái)時(shí),就計(jì)算出一個(gè)MRO有序列表,2.3之后,py3唯一支持的算法,MyClass->D->B->C->A->object;
?
多繼承的缺點(diǎn):
當(dāng)類很多,繼承復(fù)雜的情況下,繼承路徑太多,很難說(shuō)清什么樣的繼承路徑;
py語(yǔ)法允許多繼承,但py代碼是解釋執(zhí)行,只有執(zhí)行到的時(shí)候才發(fā)現(xiàn)錯(cuò)誤;
團(tuán)隊(duì)協(xié)作開發(fā),如果引入多繼承,那代碼將不可控;
不管編程語(yǔ)言是否支持多繼承,都應(yīng)避免多繼承;
py的面向?qū)ο?,太靈活了,太開放了,所以要團(tuán)隊(duì)守規(guī)矩,類增加要規(guī)范;
規(guī)范化、文檔化、大量重構(gòu);
?
多繼承定義:
class ClassName(基類列表):
???????? 類體
?
?
?
UML中,面向?qū)ο笾械母呒?jí)部分;
?
例:
Document類是其它所有文檔類的抽象基類;
Word、Pdf是Document類的子類;
要求:
為document子類提供打印能力;
?
思路1:
在Document類中提供print方法;
基類提供的方法不應(yīng)該具體實(shí)現(xiàn),因?yàn)樗幢剡m合子類的打印,子類中需要覆蓋重寫;
print算是一種能力——打印功能,不是所有的Document的子類都需要的,所以,從這個(gè)角度出發(fā),有問(wèn)題;
?
思路2:
需要打印的子類上增加;
如果在子類上直接增加,違反了ocp原則,所以應(yīng)該繼承后增加;
以下兩種不同的繼承思路,不同場(chǎng)景下用:
方一:用于項(xiàng)目正在開發(fā)中,直接加到所屬類里;
方二:用于已開發(fā)完成項(xiàng)目或第三方庫(kù),用繼承方式新增類;
看似不錯(cuò),如果還要提供其它能力,如何繼承?
應(yīng)用于網(wǎng)絡(luò),文檔應(yīng)該具備序列化的能力,類上就應(yīng)該實(shí)現(xiàn)序列化;
可序列化還可能分為使用pickle、messagepack、json等;
這時(shí)發(fā)現(xiàn),類可能太多了,繼承的方式不是很好了,功能太多,A類需要某幾樣功能,B類需要另幾樣功能,很繁瑣;
?
思路3:
裝飾器,用處極廣;
優(yōu)點(diǎn):簡(jiǎn)單方便,在需要的地方動(dòng)態(tài)增加;
用裝飾器增強(qiáng)一個(gè)類,把功能給類附加上去,哪個(gè)類需要,就裝飾它;
?
思路4:
mixin,本質(zhì)上就是多繼承實(shí)現(xiàn)的;
mixin體現(xiàn)的是一種組合的設(shè)計(jì)模式;
在面向?qū)ο蟮脑O(shè)計(jì)中,一個(gè)復(fù)雜的類,往往需要很多功能,而這些功能由來(lái)自不同的類提供,這就要將很多的類組合在一起;
從設(shè)計(jì)模式的角度來(lái)說(shuō),多組合(混在一起,如PrintableWord(PrintableMixin,Word))、少繼承,組合優(yōu)于繼承;
?
mixin類的使用原則:
mixin類中不應(yīng)該顯式的出現(xiàn)__init__初始化方法(是混進(jìn)去增強(qiáng)功能的,不用初始化,一般是用來(lái)增強(qiáng)類屬性,而不是增強(qiáng)實(shí)例的,實(shí)例缺的東西應(yīng)在其類上或繼承的類上,而不是混進(jìn)去的);
mixin類通常不能獨(dú)立工作(不完整),因?yàn)樗菧?zhǔn)備混入別的類中的部分功能實(shí)現(xiàn);
mixin類如有繼承,該mixin類的祖先類也應(yīng)是mixin類;
?
使用時(shí),mixin類通常在繼承列表的第一個(gè)位置,如class SuperPrintablePdf(SuperPrintableMixin,Pdf): pass;
?
mixin類和裝飾器:
這兩種方式都可使用,看個(gè)人喜好;
如果還需要繼承,就要使用mixin類方式;
簡(jiǎn)單用裝飾器;復(fù)雜用mixin類;
實(shí)現(xiàn)方式不同,結(jié)果一樣(殊途同歸);
?
?
思路2:方一:
class Document:
??? def __init__(self,content):
??????? self.content = content
?
??? def print(self):
??????? print(self.content)
?
class Word(Document):?? #用于項(xiàng)目正在開發(fā)中,直接加到所屬類里
??? def print(self):
??????? print('word print: {}'.format(self.content))
?
class Pdf(Document):
??? def print(self):
??????? print('pdf print: {}'.format(self.content))
?
print(Word.mro())
word = Word('test\nabc')
word.print()
print(Word.__dict__)
輸出:
[
word print: test
abc
{'__module__': '__main__', 'print':
?
思路2:方二1:
class Document:?? #第三方庫(kù)
??? def __init__(self,content):
??????? self.content = content
?
??? def print(self):
??????? print(self.content)
?
class Word(Document): pass?? #第三方庫(kù)
?
class PrintableWord(Word):
??? def print(self):
??????? print('word print: {}'.format(self.content))
?
class Pdf(Document): pass?? #第三方庫(kù)
?
class PrintablePdf(Pdf):
??? def print(self):
??????? print('pdf print: {}'.format(self.content))
?
print(PrintableWord.mro())
word = PrintableWord('test\nabc')
word.print()
print(word.__dict__)
print(PrintableWord.__dict__)
輸出:
[
word print: test
abc
{'content': 'test\nabc'}
{'__module__': '__main__', 'print':
?
思路2:方二2:
class Printable:
??? def _print(self):
??????? print(self.content)
?
class Document:
??? def __init__(self,content):
??????? self.content = content
?
??? def print(self):
??????? print(self.content)
?
class Word(Document): pass
?
class PrintableWord(Printable,Word): pass
?
class Pdf(Document): pass
?
class PrintablePdf(Printable,Pdf): pass
?
print(PrintableWord.mro())
word = PrintableWord('test\nabc')
word.print()
print(word.__dict__)
print(PrintableWord.__dict__)
輸出:
[
test
abc
{'content': 'test\nabc'}
{'__module__': '__main__', '__doc__': None}
?
思路3(函數(shù)裝飾器):
def printable(cls):
??? # def _print(self):
??? #???? print(self.content)
??? # cls.print = _print?? #等價(jià)于下面一行
??? cls.print = lambda self: print(self.content)
??? return cls
?
class Document:
??? def __init__(self,content):
??????? self.content = content
?
??? def print(self):
??????? print(self.content)
?
class Word(Document): pass
?
class Pdf(Document): pass
?
@printable
class PrintableWord(Word): pass
?
@printable
class PrintablePdf(Pdf): pass
?
word = PrintableWord('test\nabc')
word.print()
print(word.__class__.mro())
print(word.__dict__)
print(PrintableWord.__dict__)
輸出:
test
abc
[
{'content': 'test\nabc'}
{'__module__': '__main__', '__doc__': None, 'print':
?
思路4:
class PrintableMixin:
??? def print(self):??#該行和下一行的print,與builtins中沖突?不沖突,這是自定義類中的方法;若把該函數(shù)寫在與class同級(jí)下,就與builtins沖突了
????? ??print('~~~~~~~~~~~~~~~~')
??????? print(self.content)
??????? print('~~~~~~~~~~~~~~~~')
?
class Document:
??? def __init__(self,content):
??????? self.content = content
?
class Word(Document): pass
?
class PrintableWord(PrintableMixin,Word): pass??#PrintableMixin只能在前邊,如在右邊將不起作用,屬多繼承,本質(zhì)上是改變了__mro__中的順序
?
class Pdf(Document): pass
?
class PrintablePdf(PrintableMixin,Pdf): pass
?
class SuperPrintableMixin(PrintableMixin):?? #mixin是類,可繼承
??? def print(self):
??????? print('#####################')
??????? print(self.content)
??????? print('#####################')
?
class SuperPrintablePdf(SuperPrintableMixin,Pdf): pass
?
word = PrintableWord('test\nabc')
word.print()
print(word.__class__.mro())?? #查看搜索順序
print(word.__dict__)
print(word.__class__.__dict__)
?
pdf = SuperPrintablePdf('pdf\npdf')
pdf.print()
print(pdf.__class__.mro())
print(pdf.__dict__)
print(pdf.__class__.__dict__)
輸出:
~~~~~~~~~~~~~~~~
test
abc
~~~~~~~~~~~~~~~~
[
{'content': 'test\nabc'}
{'__module__': '__main__', '__doc__': None}
#####################
#####################
[
{'content': 'pdf\npdf'}
{'__module__': '__main__', '__doc__': None}
?
?
?
1、shape基類,要求所有子類都必須提供面積的計(jì)算,子類有三角形、矩形、圓;
2、上題圓類的數(shù)據(jù)可序列化;
3、用面向?qū)ο髮?shí)現(xiàn)linked list鏈表:
單向鏈表實(shí)現(xiàn)append、iternodes;
雙向鏈表實(shí)現(xiàn)append、pop、insert、remove、iternodes;
?
?
注:
pycharm中格式化,Code-->Reformat Code;
文檔字符串一般用""",雙引號(hào)三引號(hào);
?
1、
import math
?
class Shape:
??? @property
??? def area(self):
??????? # return
??????? raise NotImplementedError('base class is not implement')??#技巧,基類中未實(shí)現(xiàn)該方法,即這個(gè)父類就是不允許調(diào)用
?
class Triangle(Shape):
??? def __init__(self,bottom,height):
??????? self.bottom = bottom
??????? self.height = height
?
??? @property
??? def area(self):
?????? ?return self.bottom * self.height / 2
?
class Rectangle(Shape):
??? def __init__(self,length,width):
??????? self.length = length
??????? self.width = width
?
??? @property
??? def area(self):
??????? return self.length * self.width
?
class Circle(Shape):
??? def __init__(self,radius):
??????? self.radius = radius
?
??? @property
??? def area(self):
??????? return math.pi * (self.radius ** 2)
?
triangle = Triangle(3,2)
print(triangle.area)
?
rectangle = Rectangle(5,4)
print(rectangle.area)
?
circle = Circle(2)
print(circle.area)
輸出:
3.0
20
12.566370614359172
?
2、
import json
import msgpack
from class_practice_8 import Circle
?
class SerializableMixin:
??? def dumps(self,t='json'):
??????? if t == 'json':
??????????? return json.dumps(self.__dict__)
??????? elif t == 'msgpack':
??????????? return msgpack.dumps(self.__dict__)
??????? else:
??????????? raise NotImplementedError('Not implemented serializable')
?
class SerializableCircleMixin(SerializableMixin,Circle): pass
?
scm = SerializableCircleMixin(2)
print(scm.area)
?
print(scm.__dict__)
s = scm.dumps('msgpack')
print(s)
輸出:
12.566370614359172
{'radius': 2}
b'\x81\xa6radius\x02'
?
鏈表與列表?鏈表為什么用列表實(shí)現(xiàn)?
列表中僅保存的是鏈表中每個(gè)元素內(nèi)存地址的引用;
鏈表中每個(gè)元素之間是靠自身內(nèi)部的next聯(lián)系的;
?
單向鏈表,手拉手,有序,內(nèi)存中是亂的、分散的;
list,內(nèi)存中有序;
?
3、
single linkedlist1:
class SingleNode:
??? def __init__(self,val,next=None):
??????? self.val = val
??????? self.next = next
?
??? def __repr__(self):
??????? return str(self.val)
?
??? def __str__(self):
??????? return str(self.val)
?
class LinkedList:
?? ?def __init__(self):
??????? # self.nodes = []
??????? self.head = None
??????? self.tail = None
?
??? def append(self,val):
??????? node = SingleNode(val)
??????? if self.tail is None:
??????????? self.head = node
??????? else:
??????????? self.tail.next = node
??????? # self.nodes.append(node)
??????? self.tail = node
?
??? def iternodes(self):
??????? current = self.head
??????? while current:
??????????? yield current
??????????? current = current.next
?
ll = LinkedList()
node = SingleNode(5)
ll.append(node)
node = SingleNode(6)
ll.append(node)
for node in ll.iternodes():
??? print(node)
輸出:
5
6
?
single linkedlist2:
class SingleNode:?? #代表一個(gè)節(jié)點(diǎn)
??? def __init__(self,val,next=None):?? #最后一個(gè)為None
??????? self.val = val
??????? self.next = next?? #實(shí)例屬性,類中print和裝飾器中的_print
?
??? def __repr__(self):
??????? return str(self.val)
?
??? __str__ = __repr__
?
class LinkedList:?? #容器類,某種方式存儲(chǔ)一個(gè)個(gè)節(jié)點(diǎn)
??? def __init__(self):
??????? self.items = []?? #保存每個(gè)節(jié)點(diǎn)的地址;可用索引,便于查詢,檢索方便,但insert、remove不方便,[]適合讀多寫少;業(yè)務(wù)中如果頻繁插入元素則不用列表
??????? self.head = None
??????? self.tail = None??#追加方便
?
??? def append(self,val):
??????? node = SingleNode(val)
??????? if self.tail is None:?? #尾巴是空則該鏈表為空
??????????? self.head = node
??????? else:
??????????? self.tail.next = node
??????? self.tail = node
??????? self.items.append(node)
???????
??? def iternodes(self):?? #要知道鏈表中的元素必須迭代;技巧:generator
??????? current = self.head
??????? while current:
??????????? yield current
??????????? current = current.next
?
??? def __getitem__(self, item):??#僅用于容器,提供一種方便的接口,如索引或其它方式來(lái)用
??????? return self.items[item]
?
???????? def __len__(self):?? #很少拿長(zhǎng)度,頻繁操作長(zhǎng)度一直在變,只是大概
??????? return len(self.items)
?
ll = LinkedList()
node = SingleNode(5)
ll.append(node)
node = SingleNode(6)
ll.append(node)
for node in ll.iternodes():
??? print(node)
?
print(ll[0])
輸出:
5
6
5
2
?
?
?
?
技巧:
generator;
三目運(yùn)算符;
enumerate();
?
class SingleNode:
??? def __init__(self,val,next=None,prev=None):
??????? self.val = val
??????? self.next = next
??????? self.prev = prev
?
??? def __repr__(self):
??????? return str(self.val)
?
??? __str__ = __repr__
?
class LinkedList:
??? def __init__(self):
??????? # self.items = []
??????? self.head = None
??????? self.tail = None
?
??? def append(self,val):
??????? node = SingleNode(val)
??????? if self.tail is None:?? #第一個(gè)node,the first node
??????????? self.head = node
??????? else:
??????????? self.tail.next = node
??????????? node.prev = self.tail?? #當(dāng)前節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)
??????? self.tail = node
??????? # self.items.append(node)
?
??? def iternodes(self,reverse=False):
??????? current = self.tail if reverse else self.head??#2個(gè)技巧,generator函數(shù)和類三目運(yùn)算符
??????? while current:
??????????? yield current
??????????? current = current.prev if reverse else current.next
?
??? def pop(self):
??????? if self.tail is None:?? #鏈表中元素為0
??????????? raise Exception('Empty')
??????? tail = self.tail
??????? prev = tail.prev
??????? # next = tail.next?? #用不上,尾巴的下一個(gè)元素一定為None
??????? if prev is None:?? #尾巴的前一個(gè)元素為空,說(shuō)明該鏈表僅一個(gè)元素
??????????? self.head = None
??????????? self.tail = None?? #把當(dāng)前尾巴的元素清空后,鏈表就為空
??????? else:?? #鏈表中元素>1個(gè)
??????????? self.tail = prev
??????????? prev.next = None
??????? return tail.val
?
??? def getitem(self,index):
?? ?????if index < 0:
??????????? return None
??????? current = None
??????? for i,node in enumerate(self.iternodes()):?? #技巧
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:?? #如下四行可簡(jiǎn)寫為if current is not None: return current
??????????? return None
??????? else:
??????????? return current
?
??? def insert(self,index,val):?? #考慮當(dāng)前鏈表,0個(gè)元素,1個(gè)元素(index為0、1時(shí)),尾部追加
??????? if index < 0:
??????????? raise Exception('Error')
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:?? #鏈表中無(wú)元素,index只要大于邊界就往里追加
??????????? self.append(val)
??????????? return
??????? prev = current.prev
??????? # next = current.next
??????? node = SingleNode(val)
??????? if prev is None:?? #前加、中間加、尾部加
??????????? self.head = node
??????????? node.next = current
??????????? current.prev = node
??????? else:
??????????? node.prev = prev
??????????? node.next = current
??????????? current.prev = node
??????????? prev.next = node
?
??? def remove(self,index):
??????? if self.tail is None:
??????????? raise Exception('Empty')
??????? if index < 0:
??????????? raise ValueError('Wrong Index{}'.format(index))
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? raise ValueError('Wrong Index {} out of memory'.format(index))
??????? prev = current.prev
??????? next = current.next
??????? if prev is None and next is None:
??????????? self.head = None
??????????? self.tail = None
??????? elif prev is None:
??????????? self.head = next
??????????? next.prev = None
??????? elif next is None:
??????????? self.tail = prev
??????????? prev.next = None
??????? else:
??????????? prev.next = next
??????????? next.prev = prev
??????? del current
?
?
ll = LinkedList()
node1 = SingleNode('abc')
ll.append(node1)
node2 = SingleNode(4)
ll.append(node2)
node3 = SingleNode(5)
ll.append(node3)
node4 = SingleNode(6)
ll.append(node4)
node5 = SingleNode('end')
ll.append(node5)
?
for node in ll.iternodes():
??? print(node)
print('~'*20)
ll.pop()
ll.pop()
ll.pop()
ll.insert(0,'start')?? #各種測(cè)試,前、中、尾,元素為空,元素為1個(gè)
ll.insert(8,'end')
ll.insert(1,123)
ll.insert(2,456)
ll.remove(5)
ll.remove(0)
for node in ll.iternodes(reverse=True):
??? print(node)
輸出:
abc
4
5
6
end
~~~~~~~~~~~~~~~~~~~~
4
abc
456
123
?
?
?
1、將鏈表,封裝成容器:
要求:
1)提供__getitem__()、__iter__()、__setitem__();
2)使用一個(gè)列表,輔助完成上面的方法;
3)進(jìn)階:不使用列表,完成上面的方法;
?
2、實(shí)現(xiàn)類property裝飾器,類名稱為Property;
?
1、方一(容器實(shí)現(xiàn)):
?
class SingleNode:
??? def __init__(self,val,next=None,prev=None):
??????? self.val = val
??????? self.next = next
??????? self.prev = prev
?
??? def __repr__(self):
??????? return str(self.val)
?
??? __str__ = __repr__
?
class LinkedList:
??? def __init__(self):
??????? self.items = []
??????? self.head = None
??????? self.tail = None
??????? self.size = 0
?
??? def append(self,val):
??????? node = SingleNode(val)
??????? if self.tail is None:
??????????? self.head = node
??????? else:
??????????? self.tail.next = node
??????????? node.prev = self.tail
??????? self.tail = node
??????? self.items.append(node)
??????? self.size += 1
?
??? def iternodes(self,reverse=False):
??????? current = self.tail if reverse else self.head
??????? while current:
??????????? yield current
??????????? current = current.prev if reverse else current.next
?
??? def pop(self):
??????? if self.tail is None:
??????????? raise Exception('Empty')
??????? tail = self.tail
??????? prev = tail.prev
??????? # next = tail.next
??????? if prev is None:
??????????? self.head = None
??????????? self.tail = None
??????? else:
??????????? self.tail = prev
??????????? prev.next = None
??????? self.items.pop()
??????? self.size -= 1
??????? return tail.val
?
??? def getitem(self,index):
??????? if index < 0:
??????????? return None
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? return None
??????? else:
??????????? return current
?
??? def insert(self,index,val):
??????? if index < 0:
??????????? raise Exception('Error')
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? self.append(val)
??????????? return
??????? prev = current.prev
??????? # next = current.next
??????? node = SingleNode(val)
??????? if prev is None:
??????????? self.head = node
??????????? node.next = current
??????????? current.prev = node
??????? else:
??????????? node.prev = prev
??????????? node.next = current
??????????? current.prev = node
??????????? prev.next = node
??????? self.items.insert(index,val)
??????? self.size += 1
?
??? def remove(self,index):
??????? if self.tail is None:
??????????? raise Exception('Empty')
??????? if index < 0:
??????????? raise ValueError('Wrong Index{}'.format(index))
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? raise ValueError('Wrong Index {} out of memory'.format(index))
??????? prev = current.prev
??????? next = current.next
??????? if prev is None and next is None:
??????????? self.head = None
??????????? self.tail = None
??????? elif prev is None:
??????????? self.head = next
??????????? next.prev = None
??????? elif next is None:
??????????? self.tail = prev
??????????? prev.next = None
??????? else:
??????????? prev.next = next
??????????? next.prev = prev
??????? del current
??????? self.items.pop(index)
?? ?????self.size -= 1
?
??? def __len__(self):
??????? return self.size
?
??? # def __iter__(self):
??? #???? return iter(self.items)
??? __iter__ = iternodes
?
??? def __getitem__(self, item):
??????? return self.items[item]
?
??? def __setitem__(self, key, value):
??????? self.items[key].val = value?? #如果出錯(cuò),借用列表來(lái)拋異常,不需自己實(shí)現(xiàn)
?
ll = LinkedList()
node1 = SingleNode('abc')
ll.append(node1)
node2 = SingleNode(4)
ll.append(node2)
node3 = SingleNode(5)
ll.append(node3)
node4 = SingleNode(6)
ll.append(node4)
# ll.remove(3)
node5 = SingleNode('end')
ll.append(node5)
?
for node in ll.iternodes():
??? print(node)
print('~'*20)
ll.pop()
node6 = SingleNode('head')
ll.insert(0,node6)
node7 = SingleNode('middle')
ll.insert(3,node7)
ll.remove(3)
# print(len(ll))
for node in ll:
??? print(node)
# print(node7.next)?? #None
?
?
1、方二(非容器實(shí)現(xiàn)):
?
class SingleNode:
??? def __init__(self,val,next=None,prev=None):
??????? self.val = val
??????? self.next = next
??????? self.prev = prev
?
??? def __repr__(self):
??????? return str(self.val)
?
??? __str__ = __repr__
?
class LinkedList:
??? def __init__(self):
??????? # self.items = []
??????? self.head = None
??????? self.tail = None
??????? self.size = 0
?
??? def append(self,val):
??????? node = SingleNode(val)
??????? if self.tail is None:
??????????? self.head = node
??????? else:
??????????? self.tail.next = node
??????????? node.prev = self.tail
??????? self.tail = node
??????? # self.items.append(node)
??????? self.size += 1
?
??? def iternodes(self,reverse=False):
??????? current = self.tail if reverse else self.head
??????? while current:
??????????? yield current
??????????? current = current.prev if reverse else current.next
?
??? def pop(self):
??????? if self.tail is None:
??????????? raise Exception('Empty')
??????? tail = self.tail
??????? prev = tail.prev
??????? # next = tail.next
??????? if prev is None:
??????????? self.head = None
??????????? self.tail = None
??????? else:
??????????? self.tail = prev
??????????? prev.next = None
??????? # self.items.pop()
??????? self.size -= 1
??????? return tail.val
?
??? def getitem(self,index):
??????? if index < 0:
??????????? return None
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
???? ???????????current = node
??????????????? break
??????? if current is None:
??????????? return None
??????? else:
??????????? return current
?
??? def insert(self,index,val):
??????? if index < 0:
??????????? raise Exception('Error')
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? self.append(val)
??????????? return
??????? prev = current.prev
??????? # next = current.next
??????? node = SingleNode(val)
??????? if prev is None:
??????????? self.head = node
??????????? node.next = current
??????????? current.prev = node
??????? else:
??????????? node.prev = prev
??????????? node.next = current
? ??????????current.prev = node
??????????? prev.next = node
??????? # self.items.insert(index,val)
??????? self.size += 1
?
??? def remove(self,index):
??????? if self.tail is None:
??????????? raise Exception('Empty')
??????? if index < 0:
??????????? raise ValueError('Wrong Index{}'.format(index))
??????? current = None
??????? for i,node in enumerate(self.iternodes()):
??????????? if i == index:
??????????????? current = node
??????????????? break
??????? if current is None:
??????????? raise ValueError('Wrong Index {} out of memory'.format(index))
??????? prev = current.prev
??????? next = current.next
??????? if prev is None and next is None:
??????????? self.head = None
??????????? self.tail = None