進擊のpython
面向對象
唉,腦闊疼,昨天寫的,忘記報錯了,還要重新寫!!!!!!!
不逼逼叨了
如果此時此刻的你學過面向對象的編程
那我極力不建議你看這篇博文
因為我不想跟杠精battle
熟悉我的博文的都知道
每次要學新的東西的時候
都是從需求開始引入
那么需求來了!
我想做個游戲!
怎么玩呢?
我要有很多的狗,我還要有很多的人
狗可以咬人,人可以打狗
好,設計吧!
拋開很多不談,我們現在應該先整一只狗出來
狗有什么屬性呢?
d_name 名字
d_kind 種類
d_blod 血量
d_atta 攻擊
好,確定了屬性就整個狗!
dog = {"d_name": "ponny",
"d_kind": "erha",
"d_blod": 100,
"d_atta": 20, }
這是一只狗對吧
那我現在想要兩只狗
怎么寫?
dog = {"d_name": "ponny",
"d_kind": "erha",
"d_blod": 100,
"d_atta": 20, }
dog1 = {"d_name": "helly",
"d_kind": "laswer",
"d_blod": 100,
"d_atta": 10, }
寫完我們發現
這兩個狗的重復代碼太多了(鍵)
所以使得代碼不夠簡潔!
需要有一種方法直接把重復的放起來,只修改想改的地方
而且我這只是兩只狗
我可是要很多的狗!!!
那我們要怎么做呢?????
這個時候,是不是就想到了
我們可以用函數來做!(如果前面的函數沒看懂,別往下看!)
函數怎么做呢?
def dog(name, kind):
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": 20, }
return data
這是不是就是函數的傳參啊!沒問題吧!
那狗整出來了,人是不是也是同理的啊
def person(name, sex):
data = {"p_name": name,
"p_sex": sex,
"p_blod": 100,
"p_atta": 20, }
return data
那我又有問題了!
狗都一樣???不是吧!不同品類的狗有不同的亞子
攻擊力也就不一樣是吧
那我們就可以優化一下代碼!
dog_count = {"erha": 20,
"laswer": 10}
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
return None
return data
有問題嗎?(有問題先在這停一下,慢慢看這個代碼,看懂了再繼續)
我尋思着,怎么?狗不一樣,人就一樣了????
那就繼續優化唄!
def person(name, sex):
data = {"p_name": name,
"p_sex": sex,
"p_blod": 100,
"p_atta": 20, }
if sex == "man":
data["p_atta"] = 30
return data
上面兩個方法相當於造了兩個模子
游戲開始,你得生成一個人和狗吧,怎么生成呢?
函數的調用啊!(你看,你要是不會函數,你能看懂????)
dog1 = dog("ponny", "erha")
dog2 = dog("helly", "laswer")
person1 = person("zhangsan", "man")
我這代碼怎么個意思?
是不是整出兩只狗,再帶上一個人??
有對象了,是不是要開始寫狗咬人和人打狗了?
還是用函數的方法來寫(咋的,你就打一下啊!)
def bite(dog_obj, person_obj):
person_obj["p_blod"] -= dog_obj["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (dog_obj["d_name"], person_obj['p_name'], dog_obj["d_atta"]))
def beat(person_obj, dog_obj):
dog_obj["d_blod"] -= person_obj['p_atta']
print("[%s] 打了 瘋狗[%s],狗掉血[%s]..." % (person_obj["p_name"], dog_obj["d_name"], person_obj["p_atta"]))
(順便來了一個格式化輸出)
好了,都寫完了吧!開始玩吧(判斷血量<0死亡這種東西先不整┗|`O′|┛ 嗷~~)
dog_count = {"erha": 20,
"laswer": 10}
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
return None
return data
def person(name, sex):
data = {"p_name": name,
"p_sex": sex,
"p_blod": 100,
"p_atta": 20, }
if sex == "man":
data["p_atta"] = 30
return data
def bite(dog_obj, person_obj):
person_obj["p_blod"] -= dog_obj["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (dog_obj["d_name"], person_obj['p_name'], dog_obj["d_atta"]))
def beat(person_obj, dog_obj):
dog_obj["d_blod"] -= person_obj['p_atta']
print("[%s] 打了 瘋狗[%s],狗掉血[%s]..." % (person_obj["p_name"], dog_obj["d_name"], person_obj["p_atta"]))
dog1 = dog("ponny", "erha")
dog2 = dog("helly", "laswer")
person1 = person("zhangsan", "man")
bite(dog2, person1)
beat(person1, dog1)
功能簡直完美!!
但是你玩着玩着,你就發現
咬人這個動作(函數)
應該是狗對人的吧(當然有些人也不一定是人)
那我要是把人放進去呢?
bite(person1, dog1)
你把人傳給了只有狗能用的方法
你發現完蛋了!后面全錯了!
怎么解決呢?
可能會有人說,那我加個判斷就好了
對!
加判斷是一種方法!(自己做啊,能做出來的!)
但是我們進階的想想!
你看┗|`O′|┛ 嗷~~
這個咬人 (bite)是不是狗(dog)的動作
而且,只能是狗(dog)的!
所以 ,我們是不是可以這樣!
把咬人(bite)的方法放進狗(dog)里
這樣就變成了,你必須調用狗(dog)
才能調用咬人(bite)這個動作(函數)
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
def bite(dog_obj, person_obj):
person_obj["p_blod"] -= dog_obj["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (dog_obj["d_name"], person_obj['p_name'], dog_obj["d_atta"]))
return data
這樣雖然有點意思,但是經不起深究
首先,我必須要調用才能執行對吧!
那我就還應該加一個bite()
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
def bite(dog_obj, person_obj):
person_obj["p_blod"] -= dog_obj["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (dog_obj["d_name"], person_obj['p_name'], dog_obj["d_atta"]))
bite() # 在這呢!!!
return data
那我加完之后問題又來了!
你違背了我剛開始創建dog()這個函數的初心啊
我本意是調用這個函數,生成一個狗
你現在是調用了,就讓他去咬人!
那我想生成個不咬人的都不行!
所以,這么寫是有問題的
所以我們不應該把bite()直接放進去
應該想用bite()的時候再用
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
def bite(dog_obj, person_obj):
person_obj["p_blod"] -= dog_obj["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (dog_obj["d_name"], person_obj['p_name'], dog_obj["d_atta"]))
data["bite"] = bite ### 看這里!!!! 為了外部可以調用!!!!
return data
dog1 = dog("ponny", "erha")
print(dog1["bite"])
# <function dog.<locals>.bite at 0x051A7930>
看,是不是返回了一個函數那我要是想調用這個函數,就加個括號就行了唄
然后我們進行代碼終極優化!
dog_count = {"erha": 20,
"laswer": 10}
def dog(name, kind):
if kind in dog_count:
data = {"d_name": name,
"d_kind": kind,
"d_blod": 100,
"d_atta": dog_count[kind], }
else:
print("品種不明!")
def bite(person_obj):
person_obj["p_blod"] -= data["d_atta"]
print("瘋狗[%s]咬了[%s],掉血[%s]..." % (data["d_name"], person_obj['p_name'], data["d_atta"]))
data["bite"] = bite
return data
def person(name, sex):
data = {"p_name": name,
"p_sex": sex,
"p_blod": 100,
"p_atta": 20, }
if sex == "man":
data["p_atta"] = 30
def beat(dog_obj):
dog_obj["d_blod"] -= data['p_atta']
print("[%s] 打了 瘋狗[%s],狗掉血[%s]..." % (data["p_name"], dog_obj["d_name"], data["p_atta"]))
data["beat"] = beat
return data
dog1 = dog("ponny", "erha")
dog2 = dog("helly", "laswer")
person1 = person("zhangsan", "man")
dog1["bite"](person1)
person1["beat"](dog2)
完美實現需求對吧!!
而當你對狗傳進去狗的時候,就會報錯(自己試試!)
逼逼了這么多,有什么用呢?
跟面向對象有什么關系?
其實你上面寫的代碼就是面向對象的編程!
你在設計角色時,為了讓一個角色可以變成多個實體對象
你設計了一個基礎模板,只要傳入不同參數,就會產生不同的角色
這代表你已經開始切換成上帝視角看事情 ,上帝視角就是面向對象編程的視角
上帝要造世界萬物,他肯定不是一個一個的造出來
他肯定是設計出一個個的物種的模板,然后通過模子批量批一個個的實體造出來
造出來的實體各有特色,屬性、功能都不盡相同,有的人的貪婪、有的人好色、有的人懦弱,有的人勇猛
這些人之間會發生什么關系 ,誰和誰交媾、誰和誰打仗,上帝懶的管,上帝只控制大局
這里想說什么呢?
就是為什么要有面向對象這種編程思想?
以前我們寫程序都是用的是面向過程這種思想
就是程序從上到下一步一步的執行,一步一步從上到下,從頭到尾的解決問題
基本設計思路就是程序一開始是要着手解決的一個大的問題
然后把一個大問題分解成許多個小問題或子過程
這些子過程再繼續分解成更小的問題
以至於可以解決這個問題
舉個栗紙!
你要去上課!
是不是要起床⇨洗漱⇨拿鑰匙⇨鎖門⇨往教室走⇨到教室⇨上課
問題也是顯而易見的,就是如果你要對步驟進行修改,對你修改的那部分有依賴的各個部分你都也要跟着修改
舉個例子,你要先起床 ,別的步驟是依賴起床才能正常運行
那如果你改了起床狀態,別的步驟依賴這個步驟
那就會發生一連串的影響,隨着步驟越來越多, 維護難度會越來越高
所以一般認為,如果你只是寫一些簡單的腳本
去做一些一次性任務,用面向過程的方式是極好的,
但如果你要處理的任務是復雜的,且需要不斷迭代和維護的,那還是用面向對象最方便了
面向編程是利用“類”和“對象”來創建各種模型來實現對真實世界的描述
使用面向對象編程的原因一方面是因為它可以使程序的維護和擴展變得更簡單,並且可以大大提高程序開發效率
另外,基於面向對象的程序可以使它人更加容易理解你的代碼邏輯,從而使團隊開發變得更從容
講個小故事:
聖經記載:剛開始上帝照着自己的樣子造人(類),於是造了亞當(對象)和夏娃(對象)
而亞當(對象)和夏娃(對象)之后生出了(繼承)亞伯拉罕,之后又有猶太人... ...
面向對象的幾個核心特性如下
-
Class 類
(此處省略概念)
剛才寫的那個 dog 函數,就是 狗類
剛才寫的那個person函數,就是 人 類
-
Object 對象
(此處省略概念)
剛才的 dog1 就是對象
剛才的 dog2 就是對象
剛才的 person1 就是對象
亞當夏娃 就是對象
這兩個東西就是對現實世界的描述!比如我說狗!你就能大概知道,四條腿啊什么的
但是我要說你家的那個叫ponny的erha的那個狗
你是不是一下子就知道了他的花色啊,什么習性啊,毛啊等等的
而通過模板(類)的調用來產生實體(對象)的過程就叫做“實例化”
-
繼承
亞伯拉罕是上帝造的嗎?不是,是亞當和夏娃生的
也就繼承了亞當夏娃(對象)的許多特征
就是為了少寫代碼
-
封裝
咱們在寫咬人(bite)的時候是不是想着
這是個狗的方法
所以放在狗的函數下
只能被狗調用
所以,這個操作,就叫封裝!
這是為了安全