python學習日記(初識面向物件)
面向過程 VS 面向物件
面向過程
面向過程的程式設計把計算機程式視為一系列的命令集合,即一組函式的順序執行。為了簡化程式設計,面向過程把函式繼續切分為子函式,即把大塊函式通過切割成小塊函式來降低系統的複雜度。
面向過程的程式設計的核心是過程(流水線式思維),過程即解決問題的步驟,面向過程的設計就好比精心設計好一條流水線,考慮周全什麼時候處理什麼東西。
優點是:極大的降低了寫程式的複雜度,只需要順著要執行的步驟,堆疊程式碼即可。
缺點是:一套流水線或者流程就是用來解決一個問題,程式碼牽一髮而動全身。
應用場景:一旦完成基本很少改變的場景,著名的例子有Linux核心,git,以及Apache HTTP Server等。
面向物件
面向物件程式設計——Object Oriented Programming,簡稱OOP,是一種程式設計思想。OOP把物件作為程式的基本單元,一個物件包含了資料和操作資料的函式。
面向物件的程式設計把計算機程式視為一組物件的集合,而每個物件都可以接收其他物件發過來的訊息,並處理這些訊息,計算機程式的執行就是一系列訊息在各個物件之間傳遞。
在Python中,所有資料型別都可以視為物件,當然也可以自定義物件。自定義的物件資料型別就是面向物件中的類(Class)的概念。
優點是:解決了程式的擴充套件性。對某一個物件單獨修改,會立刻反映到整個體系中,如對遊戲中一個人物引數的特徵和技能修改都很容易。
缺點:可控性差,無法向面向過程的程式設計流水線式的可以很精準的預測問題的處理流程與結果,面向物件的程式一旦開始就由物件之間的互動解決問題,即便是上帝也無法預測最終結果。於是我們經常看到一個遊戲人某一引數的修改極有可能導致陰霸的技能出現,一刀砍死3個人,這個遊戲就失去平衡。
面向物件程式設計可以使程式的維護和擴充套件變得更簡單,並且可以大大提高程式開發效率 ,另外,基於面向物件的程式可以使它人更加容易理解你的程式碼邏輯,從而使團隊開發變得更從容。
舉例說明
我們以一個例子來說明面向過程和麵向物件在程式流程上的不同之處。
假設我們要處理學生的成績表,為了表示一個學生的成績,面向過程的程式可以用一個dict表示:
std1 = { 'name': 'Michael', 'score': 98 } std2 = { 'name': 'Bob', 'score': 81 }
而處理學生成績可以通過函式實現,比如列印學生的成績:
def print_score(std): print('%s: %s' % (std['name'], std['score']))
如果採用面向物件的程式設計思想,我們首選思考的不是程式的執行流程,而是Student
這種資料型別應該被視為一個物件,這個物件擁有name
和score
這兩個屬性(Property)。如果要列印一個學生的成績,首先必須創建出這個學生對應的物件,然後,給物件發一個print_score
訊息,讓物件自己把自己的資料打印出來。
class Student(object): def __init__(self, name, score): self.name = name self.score = score def print_score(self): print('%s: %s' % (self.name, self.score))
給物件發訊息實際上就是呼叫物件對應的關聯函式,我們稱之為物件的方法(Method)。面向物件的程式寫出來就像這樣:
bart = Student('Bart Simpson', 59) lisa = Student('Lisa Simpson', 87) bart.print_score() lisa.print_score()
面向物件的設計思想是從自然界中來的,因為在自然界中,類(Class)和例項(Instance)的概念是很自然的。Class是一種抽象概念,比如我們定義的Class——Student,是指學生這個概念,而例項(Instance)則是一個個具體的Student,比如,Bart Simpson和Lisa Simpson是兩個具體的Student。
所以,面向物件的設計思想是抽象出Class,根據Class建立Instance。
面向物件的抽象程度又比函式要高,因為一個Class既包含資料,又包含操作資料的方法。
例項來自於這裡
初識類和物件
無形中使用的類
python中一切皆為物件,型別的本質就是類,所以,不管你信不信,你已經使用了很長時間的類了
>>> dict #型別dict就是類dict <class 'dict'> >>> d=dict(name='eva') #例項化 >>> d.pop('name') #向d發一條訊息,執行d的方法pop 'eva'
從上面的例子來看,字典就是一類資料結構,我一說字典你就知道是那個用{}表示,裡面由k-v鍵值對的東西,它還具有一些增刪改查的方法。但是我一說字典你能知道字典裡具體存了哪些內容麼?不能,所以我們說對於一個類來說,它具有相同的特徵屬性和方法。
而具體的{'name':'eva'}這個字典,它是一個字典,可以使用字典的所有方法,並且裡面有了具體的值,它就是字典的一個物件。物件就是已經實實在在存在的某一個具體的個體。
在python中,用變量表示特徵,用函式表示技能,因而具有相同特徵和技能的一類事物就是‘類’,物件是則是這一類事物中具體的一個。
類的相關知識
初識類
def functionName(args): '函式文件字串' 函式體定義函式
#宣告一個類 ''' class 類名: '類的文件字串' 類體 ''' #我們建立一個類 class Data: pass
class Person: #定義一個人類 role = 'person' #人的角色屬性都是人 def walk(self): #人都可以走路,也就是有一個走路方法,也叫動態屬性 print("person is walking...")
類有兩種作用:屬性引用和例項化
屬性引用(類名.屬性)
class Person: #定義一個人類 role = 'person' #人的角色屬性都是人 def walk(self): #人都可以走路,也就是有一個走路方法 print("person is walking...") print(Person.role) #檢視人的role屬性 print(Person.walk) #引用人的走路方法,注意,這裡不是在呼叫
例項化
例項化:類名加括號就是例項化,會自動觸發__init__函式的執行,可以用它來為每個例項定製自己的特徵
class Person: # 定義一個人類 role = 'person' # 人的角色屬性都是人 def __init__(self, name): self.name = name # 每一個角色都有自己的暱稱; def walk(self): # 人都可以走路,也就是有一個走路方法 print("person is walking...") #例項化的過程就是類——>物件的過程 #語法:物件名 = 類名(引數) li = Person('libai')#例項化,類名()就等於在執行Person.__init__() #執行完__init__()就會返回一個物件。這個物件類似一個字典,存著屬於這個人本身的一些屬性和方法。 li.walk()#呼叫方法 print(li.name)#檢視屬性 直接,物件名.屬性名
關於self
self:在例項化時自動將物件/例項本身傳給__init__的第一個引數,你也可以給他起個別的名字,但是正常人都不會這麼做。
因為你的改動別人可能不認識
類屬性的補充
一:我們定義的類的屬性到底存到哪裡了?有兩種方式檢視 dir(類名):查出的是一個名字列表 類名.__dict__:查出的是一個字典,key為屬性名,value為屬性值 二:特殊的類屬性 類名.__name__# 類的名字(字串) 類名.__doc__# 類的文件字串 類名.__base__# 類的第一個父類 類名.__bases__# 類所有父類構成的元組 類名.__dict__# 類的字典屬性 類名.__module__# 類定義所在的模組 類名.__class__# 例項對應的類(僅新式類中)
物件的相關知識
物件是關於類而實際存在的一個例子,即例項
物件/例項只有一種作用:屬性引用
當然了,你也可以引用一個方法,因為方法也是一個屬性,只不過是一個類似函式的屬性,我們也管它叫動態屬性。
引用動態屬性並不是執行這個方法,要想呼叫方法和呼叫函式是一樣的,都需要在後面加上括號
class Info: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def climb(self): return ('Info:name:{},age:{} years old,{},hobby:climb moutain'.format(self.name,self.age,self.sex)) def drive(self): return ('Info:name:{},age:{} years old,{},hobby:drive the car'.format(self.name,self.age,self.sex)) def favor(self): return ('Info:name:{},age:{} years old,{},hobby:listen to music'.format(self.name,self.age,self.sex)) no1 = Info('miky','10','male') print(no1.climb()) no2 = Info('lily','12','female') print(no2.favor()) no3 = Info('rick','28','male') print(no3.drive())
物件之間的互動
人與小狗的例子
class Dog: def __init__(self,name,aggr,hp): self.dog_name = name#小狗的名字 self.dog_aggr = aggr#小狗的攻擊力 self.dog_hp = hp#小狗的生命值 def bite(self,person): person.role_hp -= dog.dog_aggr#小狗咬人,人的生命值根據小狗攻擊力下降 print('{0}被{1}咬了一口,{0}剩餘血量:{2}'.format(person.role_name,self.dog_name,person.role_hp)) dog = Dog('poppy',2,50)#例項化一隻小狗dog class Person: def __init__(self,name,aggr,hp): self.role_name = name self.role_aggr = aggr self.role_hp = hp def attack(self,dog): dog.dog_hp -= person.role_aggr print('{0}打了小狗{1}一下,小狗{1}剩餘血量:{2}'.format(self.role_name,dog.dog_name,dog.dog_hp)) person = Person('zoro',20,100)#例項化一個人物zoro print('{}當前血量:{}'.format(dog.dog_name,dog.dog_hp)) person.attack(dog) print('{}當前血量:{}'.format(person.role_name,person.role_hp)) dog.bite(person)
計算圓的周長與面積
from math import pi class Circle: # pi = 3.14 def __init__(self,r): self.radius = r def perimeter(self): return 'perimeter is :{}'.format(round(2*int(self.radius)*pi,2))#保留兩位小數 def area(self): return 'area is :{}'.format(pi*int(self.radius)**2) p = Circle(2) print(p.perimeter()) a = Circle(4) print(a.area())
小練習
餐館
# 餐館類 class Restaurant(): def __init__(self,name,type): self.restaurant_name = name self.restaurant_type = type def describle_restaurant(self):#描述前兩項資訊 print("the restaurant's name is".capitalize(),self.restaurant_name) print("the restaurant's main type is".capitalize(),self.restaurant_type) def open_restaurant(self):#列印餐館正在營業 print('the restaurant is opening now'.capitalize()) restaurant = Restaurant('over_sea'.title(),'launch') restaurant.describle_restaurant() restaurant.open_restaurant() #多家餐館 # restaurant_bf = Restaurant('good_day'.capitalize(),'breakfast') # restaurant_bf.describle_restaurant() # restaurant_din = Restaurant('slow_down'.capitalize(),'dinner') # restaurant_din.describle_restaurant()
使用者
#使用者類 class User(): location = 'california' def __init__(self,*args): self.first_name = args[0] self.last_name = args[1] self.sex = args[2] def describle_user(self):#列印使用者資訊摘要 print(self.first_name,self.last_name,self.sex,User.location) def greet_user(self):#向用戶發出個性化問候 print('hello MR.'+self.last_name,',you are from '+User.location)#+ 無縫連結,逗號有個空格 bw = User('bruce','wayne','male') bw.describle_user() bw.greet_user() #多使用者 # ts = User('tony','stark','male') # ts.describle_user() # ts.greet_user() # cap = User('rogers','steve','male') # cap.describle_user() # cap.greet_user()
餐館——就餐人數
#就餐人數 class Restaurant(): def __init__(self,name,type): self.restaurant_name = name self.restaurant_type = type self.number_served = 22#就餐人數,預設的值 def describle_restaurant(self): # print("the restaurant's name is".capitalize(),self.restaurant_name)#輸出太多資訊,暫時註釋掉 # print("the restaurant's main type is".capitalize(),self.restaurant_type)#輸出太多資訊,暫時註釋掉 print("this restaurant has served {} customers".format(self.number_served)) def open_restaurant(self): print('the restaurant is opening now'.capitalize()) def set_number_served(self,num):#手動設定就餐人數 self.number_served = num def increment_number_served(self,incre_num):#就餐人數遞增(根據情景可以增加判斷語句限定不能為負數等等) self.number_served += incre_num restaurant = Restaurant('over_sea'.title(),'launch') restaurant.describle_restaurant() restaurant.set_number_served(55) restaurant.describle_restaurant() restaurant.increment_number_served(45) restaurant.describle_restaurant()
使用者——嘗試登入次數
#登入次數 class User(): location = 'california' def __init__(self,*args): self.first_name = args[0] self.last_name = args[1] self.sex = args[2] self.login_attempts = 0#登入次數 def describle_user(self): print(self.first_name,self.last_name,self.sex,User.location,'登入次數:'+str(self.login_attempts)) def greet_user(self): print('hello MR.'+self.last_name,',you are from '+User.location)#+ 無縫連結,逗號有個空格 def increment_login_attemts(self):#登入次數每次執行一次,值加一 self.login_attempts += 1 def set_login_attempts(self):#登入次數重置 self.login_attempts = 0 bw = User('bruce','wayne','male') bw.describle_user() bw.greet_user() bw.increment_login_attemts() bw.increment_login_attemts() bw.increment_login_attemts() bw.describle_user() bw.set_login_attempts() bw.describle_user()
pass