python的類和對象
一、面向對象和面向過程
1.1面向過程的特點
優點是:極大的降低了寫程序的復雜度,只需要順著要執行的步驟,堆疊代碼即可。
缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一發而動全身。
1.2面向過程的特點
優點是:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物參數的特征和技能修改都很容易。
缺點:可控性差,無法向面向過程的程序設計流水線式的可以很精準的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題
二、類和對象
了解一些名詞:類、對象、實例、實例化
類:具有相同特征的一類事物(人、狗、老虎)
2.1類和對象定義
因而具有相同特征和技能的一類事物就是‘類’,對象是則是這一類事物中具體的一個。
class 類名:
def __init__(self,參數1,參數2):
self.對象的屬性1 = 參數1
self.對象的屬性2 = 參數2
def 方法名(self):pass
def 方法名2(self):pass
對象名 = 類名(1,2) #對象就是實例,代表一個具體的東西
#類名() : 類名+括號就是實例化一個類,相當於調用了__init__方法
#括號裏傳參數,參數不需要傳self,其他與init中的形參一一對應
#結果返回一個對象
對象名.對象的屬性1 #查看對象的屬性,直接用 對象名.屬性名 即可
對象名.方法名() #調用類中的方法,直接用 對象名.方法名() 即可
2.2類屬性的補充
一:我們定義的類的屬性到底存到哪裏了?有兩種方式查看
dir(類名):查出的是一個名字列表
類名.__dict__:查出的是一個字典,key為屬性名,value為屬性值
二:特殊的類屬性
類名.__name__# 類的名字(字符串)
類名.__doc__# 類的文檔字符串
類名.__base__# 類的第一個父類(在講繼承時會講)
類名.__bases__# 類所有父類構成的元組(在講繼承時會講)
類名.__dict__# 類的字典屬性
類名.__module__# 類定義所在的模塊
類名.__class__# 實例對應的類(僅新式類中)
lass Person: # 定義一個人類 role= ‘person‘ # 人的角色屬性都是人 def __init__(self, name, aggressivity, life_value): self.name = name # 每一個角色都有自己的昵稱; self.aggressivity = aggressivity # 每一個角色都有自己的攻擊力; self.life_value = life_value # 每一個角色都有自己的生命值; def attack(self,dog): # 人可以攻擊狗,這裏的狗也是一個對象。 # 人攻擊狗,那麽狗的生命值就會根據人的攻擊力而下降 dog.life_value -= self.aggressivity
對象/實例只有一種作用:屬性引用
egg = Person(‘egon‘,10,1000)
print(egg.name)
print(egg.aggressivity)
print(egg.life_value)
2.3對象之間的交互
class Persion: def __init__(self,name,hp,dps,sex): self.name=name self.hp=hp self.dps=dps self.sex=sex def attack(self,dog): dog.hp-=self.dps print(‘%s咬了%s,%s掉了%s點血,剩余%s點血‘ % (self.name, dog.name, dog.name, self.dps, dog.hp)) class Dog: def __init__(self,name,kind,hp,dps): self.name=name self.hp=hp self.dps=dps self.kind=kind def bit(self,persion): persion.hp-=self.dps print(‘%s咬了%s,%s掉了%s點血,剩余%s點血‘ % (self.name,persion.name, persion.name, self.dps, persion.hp)) alex=Persion(‘alex‘,250,5,‘N/A‘) ha2=Dog(‘哈士奇‘,‘藏獒‘,15000,200) print(alex.attack(ha2)) print(ha2.bit(alex))人狗大戰例子
三、類命名空間與對象、實例的命名空間
創建一個類就會創建一個類的名稱空間,用來存儲類中定義的所有名字,這些名字稱為類的屬性
而類有兩種屬性:靜態屬性和動態屬性
靜態屬性就是直接在類中定義的變量
動態屬性就是定義在類中的方法
其中類的數據屬性是共享給所有對象的
>>>id(egg.role) 4341594072 >>>id(Person.role
而類的動態屬性是綁定到所有對象的
>>>egg.attack <bound method Person.attack of <__main__.Person object at 0x101285860>> >>>Person.attack <function Person.attack at 0x10127abf8>View Code
四、面向對象的組合用法
軟件重用的重要方式除了繼承之外還有另外一種方式,即:組合
組合指的是,在一個類中以另外一個類的對象作為數據屬性,稱為類的組合
class Weapon: def prick(self, obj): # 這是該裝備的主動技能,紮死對方 obj.life_value -= 500 # 假設攻擊力是500 class Person: # 定義一個人類 role = ‘person‘ # 人的角色屬性都是人 def __init__(self, name): self.name = name # 每一個角色都有自己的昵稱; self.weapon = Weapon() # 給角色綁定一個武器; egg = Person(‘egon‘) egg.weapon.prick() #egg組合了一個武器的對象,可以直接egg.weapon來使用組合類中的所有方法給人物附加一把武器
圓環是由兩個圓組成的,圓環的面積是外面圓的面積減去內部圓的面積。圓環的周長是內部圓的周長加上外部圓的周長。
這個時候,我們就首先實現一個圓形類,計算一個圓的周長和面積。然後在"環形類"中組合圓形的實例作為自己的屬性來用
from math import pi class Circle: ‘‘‘ 定義了一個圓形類; 提供計算面積(area)和周長(perimeter)的方法 ‘‘‘ def __init__(self,radius): self.radius = radius def area(self): return pi * self.radius * self.radius def perimeter(self): return 2 * pi *self.radius circle = Circle(10) #實例化一個圓 area1 = circle.area() #計算圓面積 per1 = circle.perimeter() #計算圓周長 print(area1,per1) #打印圓面積和周長 class Ring: ‘‘‘ 定義了一個圓環類 提供圓環的面積和周長的方法 ‘‘‘ def __init__(self,radius_outside,radius_inside): self.outsid_circle = Circle(radius_outside) self.inside_circle = Circle(radius_inside) def area(self): return self.outsid_circle.area() - self.inside_circle.area() def perimeter(self): return self.outsid_circle.perimeter() + self.inside_circle.perimeter() ring = Ring(10,5) #實例化一個環形 print(ring.perimeter()) #計算環形的周長 print(ring.area()) #計算環形的面積View Code
五、面向對象的三大特性(繼承、封裝、多態)
5.1繼承
5.1.1繼承的概念
繼承是一種創建新類的方式,在python中,新建的類可以繼承一個或多個父類,父類又可稱為基類或超類,新建的類稱為派生類或子類
python中類的繼承分為:單繼承和多繼承
5.2.2繼承的定義
class ParentClass1: #定義父類 pass class ParentClass2: #定義父類 pass class SubClass1(ParentClass1): #單繼承,基類是ParentClass1,派生類是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多繼承,用逗號分隔開多個繼承的類 passView Code
5.2.3查看繼承
>>> SubClass1.__bases__ #__base__只查看從左到右繼承的第一個子類,__bases__則是查看所有繼承的父類
(<class ‘__main__.ParentClass1‘>,)
>>> SubClass2.__bases__
(<class ‘__main__.ParentClass1‘>, <class ‘__main__.ParentClass2‘>)
5.1.4繼承與抽象(先抽象再繼承)
抽象即抽取類似或者說比較像的部分。
抽象分成兩個層次:
1.將奧巴馬和梅西這倆對象比較像的部分抽取成類;
2.將人,豬,狗這三個類比較像的部分抽取成父類。
抽象最主要的作用是劃分類別(可以隔離關註點,降低復雜度)
繼承:是基於抽象的結果,通過編程語言去實現它,肯定是先經歷抽象這個過程,才能通過繼承的方式去表達出抽象的結構。
抽象只是分析和設計的過程中,一個動作或者說一種技巧,通過抽象可以得到類
5.1.5派生
當然子類也可以添加自己新的屬性或者在自己這裏重新定義這些屬性(不會影響到父類),需要註意的是,一旦重新定義了自己的屬性且與父類重名,那麽調用新增的屬性時,就以自己為準了。
class Animal: ‘‘‘ 人和狗都是動物,所以創造一個Animal基類 ‘‘‘ def __init__(self, name, aggressivity, life_value): self.name = name # 人和狗都有自己的昵稱; self.aggressivity = aggressivity # 人和狗都有自己的攻擊力; self.life_value = life_value # 人和狗都有自己的生命值; def eat(self): print(‘%s is eating‘%self.name) class Dog(Animal): ‘‘‘ 狗類,繼承Animal類 ‘‘‘ def bite(self, people): ‘‘‘ 派生:狗有咬人的技能 :param people: ‘‘‘ people.life_value -= self.aggressivity class Person(Animal): ‘‘‘ 人類,繼承Animal ‘‘‘ def attack(self, dog): ‘‘‘ 派生:人有攻擊的技能 :param dog: ‘‘‘ dog.life_value -= self.aggressivity egg = Person(‘egon‘,10,1000) ha2 = Dog(‘二楞子‘,50,1000) print(ha2.life_value) print(egg.attack(ha2)) print(ha2.life_value)View Code
5.4 鉆石繼承
繼承順序
class A(object): def test(self): print(‘from A‘) class B(A): def test(self): print(‘from B‘) class C(A): def test(self): print(‘from C‘) class D(B): def test(self): print(‘from D‘) class E(C): def test(self): print(‘from E‘) class F(D,E): # def test(self): # print(‘from F‘) pass f1=F() f1.test() print(F.__mro__) #只有新式才有這個屬性可以查看線性列表,經典類沒有這個屬性 #新式類繼承順序:F->D->B->E->C->A #經典類繼承順序:F->D->B->A->E->C #python3中統一都是新式類 #pyhon2中才分新式類與經典類繼承順序
小結:
繼承的作用
減少代碼的重用
提高代碼可讀性
規範編程模式
繼承名詞解釋
抽象:抽象即抽取類似或者說比較像的部分。是一個從具題到抽象的過程。
繼承:子類繼承了父類的方法和屬性
派生:子類在父類方法和屬性的基礎上產生了新的方法和屬性
鉆石繼承
新式類:廣度優先
經典類:深度優先
python的類和對象