~~核心编程(一):面向对象——初识~~
进击の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)的时候是不是想着
这是个狗的方法
所以放在狗的函数下
只能被狗调用
所以,这个操作,就叫封装!
这是为了安全