今日學習內容總結2.5
今日學習內容總結
經過昨天對專案的練習,我們已經對之前學習的知識進行了一個整合的體驗,因為整個專案中的程式碼與邏輯,其實都是之前學習過的知識。這個專案的完成程度,就是你對之前學習一個總結的程度。靈活運用,以及對程式設計思想的轉變是必不可少的。而今天我們將會再一次的對程式設計思想進行理解,學習內容就是面向物件。
面向物件的程式設計思想
在提出什麼是面向物件的程式設計思想之前,我們先體會一下面向物件的前戲:
比如一個簡單的狗咬人,人打狗的一個簡單的遊戲。那麼我們至少需要兩個角色,那就是人,和狗的。並且因為他們會互相攻擊,所以他們都應該有攻擊力,有生命值。同時,他們有不同的名稱,性別等。那麼怎麼去描述這種不同的角色和他們的功能。於是就有了下面這樣的一個推導過程:
# 描述人和狗 我們用字典描述 person1 = { 'name': 'jason', 'type': '猛男', 'attack_val': 100, 'life_val': 1000 } dog2 = { 'name': '匕首狗', 'type': '泰迪', 'attack_val': 50, 'life_val': 300 } # 用這種方法雖然能描述,但是每出現新的角色都要這麼寫,程式碼冗餘量會很大,所以封裝成函式 def get_person(name, gender, age, t_type, attack_val, life_val): data_dict = { 'name': name, 'gender': gender, 'age': age, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val } return data_dict def get_dog(name, t_type, attack_val, life_val): data_dict = { 'name': name, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val } return data_dict # 通過函式,就能建立不同的角色了。 p1 = get_person('jason', 'male', 18, '猛男', 800, 1000) dog1 = get_dog('小黑', '松獅犬', 300, 500) # 既然是狗咬人,人打狗的遊戲,我們就用最簡單的掉血邏輯完成 def dog_attack(dog_obj, person_obj): """ :param dog_obj: 接收一條狗 :param person_obj: 接收一個人 """ # 人的血量減去狗的攻擊力 print('當前人的血量是:%s' % person_obj.get('life_val')) person_obj['life_val'] -= dog_obj.get('attack_val') print("""狗:%s 咬了人:%s 一口 人掉血:%s 剩餘血量:%s""" `%(dog_obj.get('name'),person_obj.get('name'),dog_obj.get('attack_val'),person_obj['life_val'])) def person_attack(person_obj, dog_obj): """ :param person_obj: 接收一個人 :param dog_obj: 接收一條狗 """ print('當前狗的血量是:%s'%dog_obj.get('life_val')) dog_obj['life_val'] -= person_obj.get('attack_val') print("""人:%s 錘了狗:%s 一下 狗掉血:%s 剩餘血量:%s"""%(person_obj.get('name'),dog_obj.get('name'),person_obj.get('attack_val'),dog_obj['life_val'])) # 通過這種方式,我們就簡單的實現了這個小遊戲。但是在實際呼叫的時候 dog_attack(dog2,p1) print(p1) # 人錘狗 person_attack(p2, dog1) print(dog1) '''人呼叫了狗的攻擊動作''' # dog_attack(p1, dog1) '''狗呼叫了人的攻擊工作''' # person_attack(dog2,p2) # 所以我們為了避免這種情況出現,讓人的資料跟人的功能繫結,狗的資料跟狗的功能繫結 def get_person(name, gender, age, t_type, attack_val, life_val): # 將人的攻擊動作放在產生人的函式內 def person_attack(person_obj, dog_obj): """ :param person_obj: 接收一個人 :param dog_obj: 接收一條狗 """ print('當前狗的血量是:%s' % dog_obj.get('life_val')) dog_obj['life_val'] -= person_obj.get('attack_val') print("""人:%s 錘了狗:%s 一下 狗掉血:%s 剩餘血量:%s""" % ( person_obj.get('name'), dog_obj.get('name'), person_obj.get('attack_val'), dog_obj['life_val'])) data_dict = { 'name': name, 'gender': gender, 'age': age, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val, 'person_attack':person_attack } return data_dict def get_dog(name, t_type, attack_val, life_val): def dog_attack(dog_obj, person_obj): """ :param dog_obj: 接收一條狗 :param person_obj: 接收一個人 """ # 使用最簡答的掉血邏輯 血量減去對方攻擊力 print('當前人的血量是:%s' % person_obj.get('life_val')) person_obj['life_val'] -= dog_obj.get('attack_val') print("""狗:%s 咬了人:%s 一口 人掉血:%s 剩餘血量:%s""" % ( dog_obj.get('name'), person_obj.get('name'), dog_obj.get('attack_val'), person_obj['life_val'])) data_dict = { 'name': name, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val, 'dog_attack':dog_attack } return data_dict # 上述操作其實就是將資料與功能進行繫結,不再是所有的資料都可以呼叫任意的功能
通過上述程式碼的將資料與功能整合到一起的操作其實就是面向物件程式設計的思想。
面向過程程式設計:將程式的執行流程化,即分步操作,分步的過程中解決問題。對於面向過程的思想: 需要實現一個功能的時候,看重的是開發的步驟和過程,每一個步驟都需要自己親力親為,需要自己編寫程式碼(自己來做)。過程可以理解成是流水線,面向過程程式設計可以理解成是在建立一條流水線。
面向物件程式設計:核心就是'物件'二字,物件其實就是一個"容器" 將資料與功能整合到一起,只要是符合上述描述的事物都可以稱之為是物件。對於面向物件的思想:當需要實現一個功能的時候,看重的並不是過程和步驟,而是關心誰幫我做這件事(偷懶,找人幫我做)。python針對面向物件程式設計提供了專門的語法,識別度更高,編寫更精簡。
仔細想想會發現,python中一切皆物件,面向過程與面向物件兩者沒有優劣之分,具體要結合實際情況,甚至很多時候兩者是混合在一起的,思想佔據的比例不同而已。
類與物件
物件:資料與功能的結合體。類:即類別、種類。相當於諸多物件公有的特徵(資料、功能)。舉一個簡單的例子,一個人,叫人。同時也是一個物件。但是一群人,成為人類。每個人是不同的,但是每個人都有共同的部分,稱之為人的部分。這就體現出了類和物件的區別。從描述中我們發現,其實類也是物件。所以一切皆物件。
在程式碼層面,其實是先有類才能有物件的。
# 先定義類 後產生物件
# 學生類
class Student:
# 學生類公共的資料
school = '清華大學'
# 學生類公共的功能
def choose_course(self):
print('學生選課功能')
"""類體程式碼無需呼叫就會執行 產生類的名稱空間"""
語法結構:
'''
class 類名:
類體程式碼
1.class是定義類的關鍵字
2.類名類似於函式名 但是首字母推薦大寫 用於區分
3.類體程式碼就是存放物件公共資料和功能的地方
資料: 變數名 = 變數值
功能: 函式
'''
檢視名稱空間的方法>>>:__dict__
print(Student.__dict__) # 返回值是一個字典
print(Student.__dict__['school']) # 獲取類中的屬性
print(Student.__dict__['choose_course']) # 獲取類中的屬性
# 類獲取資料和功能有一個簡便的方式>>>:句點符
print(Student.school)
print(Student.choose_course)
產生物件的方法:類名加括號:
obj1 = Student() # 類名加括號就是在產生一個物件
obj2 = Student()
print(obj1.__dict__, obj2.__dict__) # {} {}
print(obj1.school) # 清華大學
print(obj2.school) # 清華大學
print(obj1.choose_course) # bound method
print(obj2.choose_course) # bound method
print(obj1.school) # 清華大學
print(obj2.school) # 清華大學
Student.school = '北京大學' # Student.__dict__['school'] = '北京大學' 修改名字與值的對應關係
print(obj1.school) # 北京大學
print(obj2.school) # 北京大學
物件的例項化
在類中__init__()函式叫建構函式,又叫構造方法,也可以叫初始化函式。它的作用就是初始化例項時,初始化傳入例項的的預設值。如果不寫__init__(),就會呼叫的預設為空的__init__(),說白了,這個方法不管你寫不寫,都會呼叫,而且,一旦例項化就會呼叫。
類產生物件的具體步驟:
'''
1.先建立一個沒有獨有資料的空物件 {}
2.將空物件和類括號內傳入的資料一併交給__init__執行
__init__的第一個引數就是物件本身
__init__(obj,name,age,gender)
3.將建立好的物件自動返回
'''
程式碼示例:
class Student:
def __init__(self, name, age, gender):
'''該方法就一個功能>>>:給物件新增獨有的資料'''
self.name = name # obj.__dict__['name'] = name
self.age = age # obj.__dict__['age'] = age
self.gender = gender # obj.__dict__['gender'] = gender
# 學生類公共的資料
school = '清華大學'
# 學生類公共的功能
def choose_course(self):
print('學生選課功能')
# 類中針對給物件建立獨有資料的函式名,專門定義了一個固定的方法
obj1 = Student('jason', 18, 'male')
obj2 = Student('kevin', 28, 'female')
print(obj1.__dict__)
print(obj2.__dict__)
# 針對括號內第一個形參self其實就是一個普通的變數名而已,只不過該變數名將來專門接收物件的,所以給它起了個固定的名字叫self
繫結方法:
在類中定義的函式預設都是繫結給物件使用的,就是物件來調,會自動將物件當做第一個引數傳入。
class Student:
school = '清華大學'
# __init__方法不要自己去呼叫
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print('%s正在呼叫func方法'%self.name)
def index(self):
print('%s正在呼叫index方法'%self.name)
obj1 = Student('jason', 18)
print(obj1)
obj2 = Student('kevin', 28)
# 類呼叫類中函式 有幾個引數就需要傳幾個引數
Student.func(123,222)
# 物件呼叫類中函式 會將當前呼叫的物件當做第一個引數自動傳入
obj1.func()
obj2.func()
print(obj1.func)
print(obj2.index)
# 這樣就能理解為什麼類中所有的函式第一個引數都是self