前言
在 Python入門基礎中,可能有些知識點沒聽懂扫皱。聽咏尝,你不一定能完全聽懂,但是還是那件事啸罢,不放棄编检,不拋棄,一個點聽不動扰才,好允懂,就是那一個點聽不懂。從戰(zhàn)略上要蔑視那一個點衩匣,繼續(xù)往下走......最后蕾总,總體上的勝利就是成功了。
知識不要糾結一個點琅捏,人生亦是如此生百。認真對待每一個過程,但是不要糾結過不去柄延。
面向過程
關注過程(細節(jié)) “干”
面向對象
關心解決問題的人 “找”
(1)識別對象蚀浆,找人
(2)分配職責,干活 (行為 => 數據)
(3)建立交換,調用
面向對象設計過程例子:
面向對象設計:先有具體對象市俊,再從具體對象抽象出類杨凑。
- OOA: 面向對象分析
- OOD: 面向對象設計
- OOP: 面向對象編程
類與對象
- 類: 抽象的概念
數據成員:
行為成員:
如何劃分“類”?
兩個字“行為”, 干的事情不同 (函數/方法 不同) - 對象: 具體的事物
數據成員:
行為成員:
對象與對象有什么不同摆昧?
數據不同撩满,我們都知道“對象”內存空間只存儲了“數據成員”
"""
練習1: 面向對象基礎語法
"""
class Wifi:
# 數據成員
def __init__(self, name, sex):
# self 是調用當前方法的對象地址
self.name = name # 創(chuàng)建實例變量
self.sex = sex
# 行為成員
def play(self):
print(self.name + "玩耍") # 調用實例變量
# 創(chuàng)建對象,實際在調用 __init__ 方法
w01 = Wifi("莉莉", "女") # 自動將對象地址傳入方法
w01.play() # 自動將對象地址傳入方法
實例成員與類成員
也稱為實例變量與類變量
- 實例變量
練習對象的數據成員修改:
實例成員也就是對象成員绅你,實例成員包括兩種:實例變量 + 實例方法 - 實例變量語法
定義:只要遵循 對象.變量名 就是在定義實例變量:
#(1)首次通過對象創(chuàng)建后賦值伺帘。(不鼓勵)
w01 = Wife()
w01.name = "小張" # 這種語法可以,但是不鼓勵<删狻B贰!
#(2)通常做法是構造函數(__init__)中創(chuàng)建汉规。
def __init__(self, name)
self.name = name
# (3) 每個對象存儲一份礼殊,通過對象地址調用
- 實例方法
實例方法表示對象的行為。同一個方法针史,操作不同的數據晶伦。
無論創(chuàng)建多少個對象,方法都只有一份啄枕,并且被所有對象共享
-
類成員
類成員包括: 類變量 + 類方法
重點婚陪,類變量在方法區(qū)共用,對象變量獨自開辟一個變量內存
語法
定義:在類中频祝,方法外定義的變量都叫做“類變量”泌参。
class 類名:
變量名 = 表達式
調用:類名.變量名
不建議通過對象訪問類變量作用
只存儲一份在類中,被所有對象共享常空。類方法
定義:
@classmethod
def 方法名稱(cls, 參數列表)
"""
練習4: 實例變量與類變量
"""
class ICBC:
# 定義“類變量”沽一,類共用的變量
total_money = 1200000
# 定義類方法
@classmethod
def get_total_money(cls):
print("總行還剩余:%d 元" % cls.total_money)
# 定義類實例構造函數
def __init__(self, name, money):
self.name = name # 定義“實例變量”
self.money = money
ICBC.total_money -= money # 調用“類變量”,直接用類名
# 定義實例方法
def print(self):
print("%s銀行存款為:%d" % (self.name, self.money)) # 調用“實例變量”
bank01 = ICBC('曹操分行', 100000)
bank01.print()
bank02 = ICBC('劉備分行', 20000)
bank02.print()
bank03 = ICBC('孫權分行', 80000)
bank03.print()
ICBC.get_total_money()
-
類靜態(tài)方法
定義:
class 類名
@staticmethod
def 靜態(tài)方法名
方法體
作用:將函數移入類中雪隧,函數既不屬于類方法儒将,又不屬于對象方法,即可以定義為類靜態(tài)方法鹦付。
class Vector:
"""
二維向量
可以表示位置/方向
"""
def __init__(self, x, y):
self.x = x
self.y = y
# 靜態(tài)方法:表示左邊方向
@staticmethod
def left():
return Vector(0, -1)
# 靜態(tài)方法:表示右邊方向
@staticmethod
def right():
return Vector(0, 1)
封裝
從數據角度講昆禽,將一些基本數據類型復合成一個自定義類型
或者說:“將多個變量封裝到一個自定義類中”
封裝數據(類):
例如: 老婆(姓名蝗蛙,年齡,性別)
敵人(姓名醉鳖,血量捡硅,攻擊力,防御力)
二維向量 (x, y)
面向方法盗棵,只能就叫“存儲數據”,例如壮韭,字典北发、列表。
封裝數據(類)好處:可以用一個類名來表示你封裝后的產物泰涂,代碼結果清晰,事務更加明確辐怕。
優(yōu)勢:更符合人類的思考方式逼蒙。
將數據與對數據的操作整合在一起。從行為角度講寄疏,類向外提供必要(public)的功能是牢,隱藏(private)實現的細節(jié)。
封裝行為:例如陕截,二維列表助手類(獲取多個元素)
向量(向左驳棱,向右.....)
好處:以“模塊化”的方式進行編程(類似一個函數只做一件事情),一個大的需求农曲,需要分而治之社搅。我們可以不用理會一個“模塊”內部是怎么做的,只需要知道怎么用就可以乳规,把模塊串聯起來即可形葬。可以集中精力設計暮的、組織笙以、指揮多個類協(xié)調工作。
- 私有成員
做法: 命名使用雙下劃線開頭冻辩。只是一種規(guī)定猖腕,實際還是可以訪問到。
def __私有方法
__私有變量
重點:這里因為外層已經把 y 定義為類變量了恨闪,self.y = property 對象倘感, 9999 賦值給 property 對象
8假如沒有類變量 y (或者 類變量 y = 1000),這時 self.y 就屬于 init 方法內部變量
self.y 關鍵在于看看它本身是什么
"""
練習10:封裝練習 - 私有成員 - property
"""
class MyClass:
def __init__(self):
# 重點:這里因為外層已經把 y 定義為類變量了咙咽,self.y = property 對象侠仇, 9999 賦值給 property 對象
# 假如沒有類變量 y (或者 類變量 y = 1000),這時 self.y 就屬于 __init__ 方法內部變量
# self.y 關鍵在于看看它本身是什么
self.y = 9999
def get_y(self):
return self.__y
def set_y(self, value):
self.__y = value
y = property(get_y, set_y)
my01 = MyClass()
print(my01.__dict__)
-
封裝 - 只讀犁珠,只寫屬性
- property 私有屬性
property 私有屬性可以讓對象可以像操作“公開的實例變量”一樣處理“私有屬性” (2 個方法), 即是兩個公開的屬性逻炊,保護一個私有的變量
--@property 負責讀取,@屬性名.setter 負責寫入
--只寫:屬性名=property(None, 寫入方法名) - property 私有屬性定義:
@property
def name(self):
return self.__name
@name.setter
def name(self, value)
self.__name = value
- 使用 @property 封裝私有變量
class Enemy:
def __init__(self, name, attack, blood):
self.name = name
self.attack = attack
self.blood = blood
@property
def attack(self, value):
self.__attack = value
@attack.setter
def attack(self, value):
if 10 <= value <= 50:
self.__attack = value
else:
raise ValueError("攻擊力范圍錯誤")
@property
def blood(self):
return self.__blood
@blood.setter
def blood(self, value):
if 100 <= value <= 200:
self.__blood = value
else:
raise ValueError("血量范圍錯誤")
enemy01 = Enemy('骷髏頭', 50, 100)
enemy01.blood = 120
print(enemy01.__dict__)
從設計角度講封裝的思想(重點)
(1)分而治之(總思想:分)
---將一個大的需求分解為許多類犁享,每一個類處理一個獨立的功能余素。
---拆分的好處:便于分工,便于復用炊昆,可擴展性強桨吊。
---思想指導:活字印刷術
(2)變則疏之(對第一點補充威根,“分”的“度”,“點”在哪视乐?變)
---分而治之洛搀,分得有一個“度”,什么時候該拆分成一個小的分類佑淀,就看它會不會變化留美,會變化就拆分成一個小的分類。
---變化的地方獨立封裝伸刃,避免影響其他的類
---分得精髓在乎一個“變”字
(3) 高內聚(審查評價評價上面兩步驟做得好嗎谎砾?)
---內聚:一個類的內部干了多少件事
---高:一個類干的事情都能凝聚到一個點,叫“高”
---高內聚:類中的各個方法都在完成一項任務(單一職責)
---高內聚:評價一個類的內部是否都只做“一件事情”
---若不是捧颅,重構景图,提出去!!!
(4)低耦合 (講的是類與類之間的關系,十有八九在說設計模式)
---類與類的關聯性與依賴度要低
例如:硬件高度集成化碉哑,又要可插拔
最高的內聚莫過于類中只有1個方法挚币,將會導致高內聚高耦合。
最低的耦合莫過于類中包含所有的方法扣典,將會導致低耦合低內聚忘晤。
所有高內聚,低耦合講究一個平衡激捏。
- slots: 限制類創(chuàng)建的對象只能有固定的類實例變量
體會: 對象區(qū)分數據的不同
"""
練習12:封裝練習 - 體會變化點是數據的不同還是行為的不同
張無忌 教 趙敏 九陽神功
趙敏 教 張無忌 化妝
張無忌 上班 掙了 10000
趙敏 上班 掙了 8000
體會: 對象區(qū)分數據的不同
"""
class Person:
def __init__(self, name):
self.name = name
def teach(self, other, action):
print("%s 教 %s %s" % (self.name, other.name, action))
def work(self, money):
print("%s 上班设塔,掙了 %d 元" % (self.name, money))
p1 = Person('張無忌')
p2 = Person('趙敏')
p1.teach(p2, '九陽神功')
p2.teach(p1, '化妝')
p1.work(10000)
p2.work(8000)
體會: 類區(qū)別行為的不同
"""
練習13:封裝練習 - 體會變化點是數據的不同還是行為的不同
玩家(攻擊力) 攻擊 敵人(血量), 受傷(掉血)远舅,還可能死亡(掉裝備)
敵人(攻擊力) 攻擊 玩家(血量)闰蛔, 受傷(掉血/碎屏),還可能死亡
體會: 類區(qū)別行為的不同
"""
class Player:
def __init__(self, atk, hp):
self.atk = atk
self.hp = hp
def attack(self, other):
print("玩家攻打敵人:")
other.damage(self.atk)
def damage(self, atk):
self.hp -= atk
if self.hp <= 0:
self.__death()
@staticmethod
def __death(self):
print("玩家死亡")
print("游戲結束")
class Enemy:
def __init__(self, atk, hp):
self.atk = atk
self.hp = hp
def damage(self, atk):
self.hp -= atk
print("敵人受傷了:")
if self.hp <= 0:
self.__die()
@staticmethod
def __die():
print("敵人死亡")
print("掉裝備")
def attack(self, other):
print("敵人攻打玩家:")
other.damage(self.atk)
player = Player(100, 1000)
enemy = Enemy(10, 200)
player.attack(enemy)
enemy.attack(player)
player.attack(enemy)