Python學習之面向對象(封裝、繼承、多態)
面向對象
關于面向對象大家應該很熟知,即使說不出他的概念,但是至少記住他的三大特征:封裝、繼承、多態。
封裝
所謂封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。
類的定義
class ClassName(object): pass
1
2
class定義類的關鍵字.
ClassName類名,類名的每個單詞的首字母大寫(駝峰規則).
object是父類名,object是一切類的基類。在python3中如果繼承類是基類可以省略不寫。
pass 是類身體,由變量(類變量、實例變量)、方法組成(實例方法、靜態方法、類方法)
class Animal(): eye=2 #類變量 def __init__(self,name): self.animalName=name#實例變量 print("我是初始化方法,也可以叫我構造器") def move(self): print("我是實例方法") @staticmethod def eat(food): Animal.eye print("我是靜態方法:",Animal.eye) @classmethod def run(cls): print("我是類方法:",cls.eye)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
定義一個Animal類:
類變量:類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作為實例變量使用。
實例變量:定義在方法中的變量,屬于實例。
初始化方法__init__:被稱為類的構造函數或初始化方法,當創建了這個類的實例時就會調用該方法。
實例方法:類的實例化對象調用,
self:代表類的實例,而非類本身,self 在定義實例方法時是必須有的,雖然在調用時不必傳入相應的參數。
靜態方法:用@staticmethod修飾,類可以不用實例化就可以調用該方法,當然也可以實例化調用,不強制要求傳遞參數。
類方法:用@classmethod修飾,不需要 self 參數,但第一個參數需要是表示自身類的 cls 參數。
類的實例化
沒有new關鍵字,只需要一個實例名來接收類,并且賦上需要初始的值
dog=Animal("阿黃") cat=Animal("喵喵")
1
2
實例方法的調用:
當實例調用時,默認將當前實例傳進去。
類調用時,只能以 類名.method(類實例) 形式調用。
dog.move() cat.move()
1
2
靜態方法的調用:實例和類調用,沒有默認的參數傳進函數
Anmial.eat() dog.eat()
1
2
類方法的調用:
當實例調用classmethod方法時,默認會把當前實例所對應的類傳進去,
當類調用classmethod方法時,默認把此類傳進去。
Anmial.run() dog.eat()
1
2
至于__init__(),是在實例化對象時自動調用
print(dog.eye)#2 print(dog.animalName)#阿黃 print(cat.eye)#2 print(cat.animalName)#喵喵
1
2
3
4
class Animal(): eye=2 #類變量 def __init__(self,name): self.animalName=name#實例變量 print("我是初始化方法,也可以叫我構造器") def move(self,way): print("我是實例方法:","%s在%s移動"%(self.animalName,way)) @staticmethod def eat(self,food): Animal.eye print("我是靜態方法:","%s吃%s"%(self.animalName,food)) @classmethod def run(cls,self): print("我是類方法:","%s有%s只眼睛"%(self.animalName,cls.eye)) dog=Animal("阿黃")#我是初始化方法,也可以叫我構造器 cat=Animal("喵喵")#我是初始化方法,也可以叫我構造器 dog.move("馬路上")#我是實例方法: 阿黃在馬路上移動 Animal.eat(dog,"骨頭")#我是靜態方法: 阿黃吃骨頭 Animal.eat(cat,"小魚")#我是靜態方法: 喵喵吃小魚 Animal.run(dog)#我是類方法: 阿黃有2只眼睛 Animal.run(cat)#我是類方法: 喵喵有2只眼睛
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
類的私有屬性和私有方法
對于python中的類屬性,或者方法,可以通過雙下劃線_或者單下劃線來實現一定程度的私有化。
_:以單下劃線開頭只能允許其本身與子類進行訪問,(對于實例只是隱藏起來了,可訪問,可修改)。(protected)
__:以雙下劃線開頭只能允許類本身調用,類的實例不能直接調用。(private)
python 的私有不是真正的私有,只是約定俗稱的規則。即使私有了我們依然可以通過
dog._Animal__leg(但是dog._Animal_a 不可以訪問)來訪問私有變量__leg。當然設計者也可以在類中設置方法讓訪問者操作私有屬性。
示例:
class Animal(): __leg="四條腿" _eye="兩只眼睛" def __init__(self,name): self.__name=name def get__leg(self): return self.__leg def set__leg(self,leg): self.__leg=leg def __play(self): print("%s在玩"%self.__name) dog=Animal("小狗") print(dog._eye)#兩只眼睛 print(dog.get__leg())#四條腿 print(dog._Animal__leg)#四條腿 #print(dog._Animal_eye)#AttributeError: 'Animal' object has no attribute '_Animal_eye' dog.set__leg("三條腿") print(dog.get__leg())#三條腿 print(dog._Animal__name)#小狗 dog._Animal__play()#小狗在玩 print(dog.__dict__)#{'_Animal__name': '小狗', '_Animal__leg': '三條腿'} print(dir(dog))#dir查看類的所有屬性和方法 ['_Animal__leg', '_Animal__name', '_Animal__play', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_eye', 'get__leg', 'set__leg'] 從上述也可以看出__leg ,在內存中是_Animal__leg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
注:前后都有雙下劃線的是python的特殊方法如__init__(), __del__()等。
繼承:
繼承是指這樣一種能力:它可以使用現有類的所有功能,并在無需重新編寫原來的類的情況下對這些功能進行擴展。
python的繼承分單繼承和多繼承。
示例:
class man(): __sing="唱歌" _dance="跳舞" def __init__(self,name,age): self.name=name self.age=age def say(self): print("我是%s,我%s歲。"%(self.name,self.age)) class son(man): def __init__(self,sex,name,age): self.sex=sex super().__init__(name,age) class girl(man): pass son=son("男","張三",12) son.say()#我是張三,我12歲。 girl=girl("小紅",14) girl.say()#我是小紅,我14歲。 print(sorted(dir(son),reverse=True)) #['sex', 'say', 'name', 'age', '_man__sing', '_dance', '__weakref__', '__subclasshook__', '__str__', '__sizeof__', '__setattr__', '__repr__', '__reduce_ex__', '__reduce__', '__new__', '__ne__', '__module__', '__lt__', '__le__', '__init_subclass__', '__init__', '__hash__', '__gt__', '__getattribute__', '__ge__', '__format__', '__eq__', '__doc__', '__dir__', '__dict__', '__delattr__', '__class__']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
son,girl都繼承了man的屬性和方法,從dir(son)可看出,__sing沒有繼承,_dance繼承了。
我舉了一個祖孫三代的例子:
爺爺有一個名字,會說話,會踢足球;父親繼承了爺爺,但是會跑,并且重寫了play方法會打籃球;小朋友是父親的兒子,繼承了父親,自然也繼承了爺爺,但是他并不會打籃球,他會踢足球。問題來了,爺爺和父親都有play(),小朋友到底繼承了誰的play()?
首先請看示例:
class Grandpa(): def __init__(self,name): self.name=name def say(self): print("%s會說話"%self.name) def play(self): print("%s會踢足球"%self.name) class Father(Grandpa): def run(self): print("%s會跑了"%self.name) def play(self): print("%s會打籃球"%self.name) class Child(Father,Grandpa): def play(self): #super(Child, self).play() super(Father, self).play() print(Child.__mro__)#(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我們可以通過Child.__mro__打印Child的繼承路線:(請記住這個繼承順序,不能亂)
(
1
首先小朋友是他自己,其次他是Father的孩子,其次是Granpa的孫子,再其次他的祖先是object,這個繼承順序不能亂,就像祖孫三代的關系不能亂。
默認小盆友是繼承了父親的打籃球,但是我現在希望的是小盆友是繼承爺爺的踢足球,那就要重寫play方法,修改繼承順序:
super(Father, self).play() #super里寫的Father并不是繼承Father,而是Father的上一輩Grandpa #默認是這個樣子的 super(Child, self).play()
1
2
3
4
5
其實可以直接用類名調用相應的play方法(這樣child就既會踢足球又會打籃球了)如:
def play(self): Grandpa.play(self) Father.play(self)
1
2
3
當然繼承里也不能這樣寫Child(Grandpa,Father)
因為這樣寫的繼承順序是:
(
1
系統會報錯:
TypeError: Cannot create a consistent method resolution
order (MRO) for bases Grandpa, Father
假如Father又有了一個實例屬性age(其他都省略,我們只討論init())
class Grandpa(): def __init__(self,name): self.name=name class Father(Grandpa): def __init__(self,age,name): self.age=age super().__init__(name) class Child(Father,Grandpa): '''def __init__(self,age,name): super().__init__(age) super(Father, self).__init__(name)''' def sing(self): print("我叫%s,我今年%s歲"%(self.name,self.age)) c=Child(12,"xfy") c.sing() f=Father(12,"f") print(f.name)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Father自己有了__init__(),重寫了Granpa的__init__(),所以要調用Grandpa的__init__(),這樣Child就默認繼承了Father的__init__(),他就有了name和age。
多態:
所謂多態就是指一個類實例的相同方法在不同情形有不同表現形式。多態機制使具有不同內部結構的對象可以共享相同的外部接口。這意味著,雖然針對不同對象的具體操作不同,但通過一個公共的類,它們(那些操作)可以通過相同的方式予以調用。
python的多態并沒什么好講的
當派生類,重寫了基類的方法時就實現了多態性。(子類重寫父類方法)
python的封裝、繼承、多態就先告一段落,有任何疑問都可以留言評論。
Python 面向對象編程
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。