你们好,下面我说一下我对面向对象的理解,不会讲的很详细,由于有不少人的博客都把他写的很详细了,因此,我尽量简单的经过一些代码让初学者能够理解面向对象及他的三个要素。python
摘要:
1、首先介绍一下面向对象 2、而后分别讲一下封装、继承和多态 3、最后经过一段面向对象的案例来更好的理解一下面向对象
python是一门面向对象编程语言,对面相对象语言编码的过程叫作面向对象编程。编程
面向对象时一种思想,与之相对对的是面向过程。咱们先简单说一下面向过程。小程序
面向过程其实就是把过程当作设计核心,根据问题的发展顺序,依次解决问题,尽量的把过程当中涉及到的问题完善解决。他有他的优势,当拿到一个问题时,能够方便的按执行的步骤写代码,可是当逻辑关系变得复杂时,有一个地方出现差错就会致使整个程序无从下手。安全
既然主要是说python,那咱们仍是回来讲说python的面向对象,面向对象的编程语言仍是不少的,例如C++、Java等等。编程语言
面向对象程序设计把计算机程序的执行看作一组对象的集合,每一个对象之间进行消息的传送处理。有一个显著的优势就是,对某个对象进行修改,整个程序不会受到影响,自定义数据类型就是面向对象中的类的概念,而咱们须要把他们的接口处理好就很好办了。说了这么多话,有些小白已经看不下去了,那接下来咱们进入主题。ide
1 # 我认为仍是经过个例子更容易让人理解 2 3 # 首先咱们定义一个类 4 class A(object): # 这是一个类,class是建立一个类的标志 5 # 类变量(类属性):类属性是指类的属性,属性就是咱们刚学编程的时候听过的变量。 6 x = 7 7 y = "asdf" 8 9 def __init__(self,name,age): 10 self.name = name 11 self.age = age 12 13 # 方法:方法就是在类外面咱们写的函数,放在类里就叫作一个方法 14 def func(self): 15 c = 8 # 实例变量:定义在方法中的变量只做用于当前实例的类 16 print("Hello World!") 17 18 a = A() # 建立一个对象,实例化
上面的部分代码还须要再解释一下:函数
含义:对外面隐藏对象的属性和方法,仅提供接口。学习
做用:安全性(经过私有变量改变对外的使用),复用性ui
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Student(object): 5 def __init__(self, name, score): 6 # 属性仅前面有两个下划线表明私有变量,外部没法访问,所以咱们定义了两个新的方法,这样能够避免外部经过score乱改分数,仅当咱们本身知道接口才能够修改 7 self.__name = name 8 self.__score = score 9 10 def info(self): 11 print('name: %s ; score: %d' % (self.__name,self.__score)) 12 13 def getScore(self): 14 return self.__score 15 16 def setScore(self, score): 17 self.__score = score 18 19 stu = Student('Tom',99) 20 print('修改前分数:',stu.getScore()) 21 stu.info() 22 stu.setScore(59) 23 print('修改后分数:',stu.getScore()) 24 stu.info()
封装仍是比较好理解的,不过其中还有一些,好比析构函数,重写等等知识点最好在官方文档过一遍。编码
前面咱们提到过,面向对象编程有个好处就是代码复用,而其中一种方法就是经过继承机制。继承就是说定义的一个新类,继承现有的类,得到现有类的非私有属性、方法。提到个私有,就是上面提到的那个前面加两个下划线的那个东西,他在外部没法调用,继承他的子类也不能。被继承的那个类称为基类、父类或超类,子类也能够叫作派生类。
一、在继承中,基类的构造方法(__init__()方法)不会被自动调用,须要在子类的构造方法中专门调用。
二、在调用基类的方法时须要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通函数时不须要带self参数。
三、在python中,首先查找对应类型的方法,若是在子类中找不到对应的方法,才到基类中逐个查找。
直接上代码,仔细理解一下里面的关系,我把讲解都写在注释的地方。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 # 这是定义了一个基类 5 class Person(object): 6 def __init__(self, name, age, money): 7 self.name = name 8 self.age = age 9 self.__money = money # 私有属性 10 # 被引入时,继承不了,但他们的set,get函数能够继承 11 12 def setMoney(self,money): 13 self.__money = money 14 15 def getMoney(self): 16 return self.__money 17 18 def run(self): 19 print("run") 20 21 def eat(self): 22 print("eat")
下面是定义的一个子类,继承自上方的类,来使用父类中的方法和属性:
1 # 因为我将每一个类写在了不一样的文件里,因此须要引入一下,这就和咱们调用库同样 2 from 单继承的实现.person import Person 3 4 class Student(Person): 5 def __init__(self,name,age,stuid,money): 6 # 调用父类中的__init__(),supper括号中的内容,在python3之后能够不写,写上更安全些 7 super(Student,self).__init__(name,age,money) # 让父类的self当作子类的对象 8 # 子类能够由一些本身独有的属性或者方法 9 self.stuid = stuid
建立对象,经过子类使用父类的属性和方法:
1 from 单继承的实现.student import Student 2 3 stu = Student('Tom',18,111,999) # 建立Student对象 4 # 下列方法和属性均是在父类Person中定义的,在Student继承以后,即可以直接使用 5 print(stu.name, stu.age) 6 stu.run() 7 print(stu.getMoney())
上面的单继承要多理解一下,单继承理解了以后,多继承也就没什么了。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Father(object): 5 def __init__(self,money): 6 self.money = money 7 def play(self): 8 print("play") 9 def func(self): 10 print("func1") 11 12 class Mother(object): 13 def __init__(self,facevalue): 14 self.facevalue = facevalue 15 def eat(self): 16 print("eat") 17 def func(self): 18 print("func2") 19 20 21 class Children(Father,Mother): 22 def __init__(self,money,facevalue): 23 # 多继承时调用父类的属性 24 Father.__init__(self,money) 25 Mother.__init__(self,facevalue) 26 27 def main(): 28 c = Children(300,100) 29 print(c.money,c.facevalue) 30 c.play() 31 c.eat() 32 # 注意:若是多个父类中有相同的方法名,默认调用括号中前面的类 33 c.func() 34 if __name__ == "__main__": 35 main()
1 class Animal(object): 2 def __init__(self, name): 3 self.name = name 4 5 def run(self): 6 pass 7 8 def animalRun(self): 9 self.run() 10 11 12 class Cat(Animal): 13 def run(self): 14 print('cat is running') 15 16 17 class Dog(Animal): 18 def run(self): 19 print('dog is running') 20 21 22 d = Dog('dog') 23 c = Cat('cat') 24 25 Animal.animalRun(c) 26 Animal.animalRun(d)
下面给一个小程序,是模拟反恐精英,保卫者和敌人。主要是让你们看明白,只有简单的几个功能,但愿你们能够从中理解面向对象的思想。python中,任何都是对象。
首先,这是个人几个类模块,分开来写比较清晰一点,写在一块儿也是没问题的。接下来咱们一点一点的分析:
。。。。。。。。。。
得有人,好人和坏人
。。。。。。。。。。
人得有武器,先给他们两种:枪和手榴弹
。。。。。。。。。。
枪还有个弹夹也能够做为对象
。。。。。。。。。。
想一想还有什么,差很少了吧,那么咱们就开始写,想到什么再补充
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.person import Person 5 6 class Gengster(Person): 7 8 # 初始化,血量默认为100 9 def __init__(self, gun, grenade, blood=100): 10 self.gun = gun 11 self.grenade = grenade 12 self.blood = blood 13 14 # 人有开枪的功能 15 def fire(self,person): 16 person.blood.amount -= 5 # 对谁开枪,那我的就要减血 17 self.gun.shoot() # 这我的开枪,这又调用了枪的类,关于子弹的减小在枪的类里 18 19 # 扔手榴弹,其实是和枪同样的 20 def fire2(self,person): 21 person.blood -= 10 22 self.grenade.damage() # 一样经过另外一个类来控制数量的减小,使代码看起来简洁点 23 24 # 给弹夹里加子弹 25 def fillbullet(self): 26 self.gun.bulletbox.bulletcount += 10 27 28 # 补血,并保证满血只能是100 29 def fillblood(self,num): 30 self.blood += num 31 if self.blood > 100: 32 self.blood = 100 33 print("补血后血量:" + str(self.blood))
1 # 主要注释和上一个相似,这里不赘述 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 from cs.person import Person 7 8 class Profector(Person): 9 10 def __init__(self, gun, grenade, blood = 100): 11 self.gun = gun 12 self.grenade = grenade 13 self.blood = blood 14 15 def fire(self, person): 16 person.blood -= 5 17 self.gun.shoot() 18 print(str(person) + "血量减小5,剩余" + str(person.blood) ) 19 20 def fire2(self,person): 21 person.blood -= 10 22 self.grenade.damage() 23 24 def fillbullet(self): 25 self.gun.bulletbox.bulletcount += 10 26 27 def fillblood(self,num): 28 self.blood += num 29 if self.blood > 100: 30 self.blood = 100 31 print("补血后血量:" + str(self.blood))
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Gun(object): 5 6 # 初始化,把弹夹放里面,经过人来控制枪,再来控制弹夹 7 def __init__(self,bulletbox): 8 self.bulletbox = bulletbox 9 10 def shoot(self): 11 if self.bulletbox.bulletcount == 0: 12 print('没子弹了') 13 else: 14 self.bulletbox.bulletcount -= 1 15 print(str(self) + '开一枪,还剩%d颗子弹' % (self.bulletbox.bulletcount))
1 # 与枪相似 2 3 #!/usr/bin/env python 4 # -*- coding:utf-8 -*- 5 6 class Grenade(object): 7 8 def __init__(self,grenadecount): 9 self.grenadecount = grenadecount 10 11 def damage(self): 12 if self.grenadecount == 0: 13 print('手雷没有了') 14 else: 15 self.grenadecount -= 1 16 print(str(self) + "轰他一炮,手雷还剩%d颗" % (self.grenadecount))
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Bulletbox(object): 5 6 # 弹夹只需控制数量就行了 7 def __init__(self,bulletcount): 8 self.bulletcount = bulletcount
这下差很少了,人也有了,武器也有了,能够开展了
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.grenade import Grenade 5 from cs.gun import Gun 6 from cs.bulletbox import Bulletbox 7 from cs.gengster import Gengster 8 from cs.profector import Profector 9 # 参数:枪,手榴弹,血(默认100,且上限为100) 10 11 # 建立弹夹,枪,手榴弹的对象,以备人使用 12 bulletbox = Bulletbox(10) 13 gun = Gun(bulletbox) 14 grenade = Grenade(20) 15 16 # 建立人对象 17 good1 = Profector(gun,grenade) 18 good2 = Profector(gun,grenade) 19 bad1 = Gengster(gun,grenade) 20 bad2 = Gengster(gun,grenade) 21 22 print("好人1开枪打坏人1和2") 23 good1.fire(bad1) 24 good1.fire(bad2) 25 print("好人2开枪打坏人1和2") 26 good2.fire(bad1) 27 good2.fire(bad2) 28 print("坏人1炸好人1和2") 29 bad1.fire2(good1) 30 bad1.fire2(good2) 31 print("坏人2炸好人1和2") 32 bad2.fire2(good1) 33 bad2.fire2(good2) 34 print("坏人1补血3个") 35 bad1.fillblood(3)
如今这一套流程就结束了,刚开始看也许看不太懂,要仔细看一下每一个类之间的关系,先想清楚了,再来看代码是如何实现的
有没有看出来点区别,面向过程编程是就事论事,而面向对象,先把对象找出来,经过对象之间的关系把他们联系起来。想一想若是要用面向过程来实现这个,代码会写成什么样子呢。
然而并无结束,记不记得前面的类中有两对是比较相似的,好人和坏人,枪和手榴弹(这个里面的类还不太同样),那么想到了什么没有,前面提到的继承的优势是什么来着,----复用。咱们能够能够用继承来写一下呢,若是你说这个也没少几行代码嘛,那么,若是在实际当中你要建立成百上千的对象呢,难道还要每一个都复制粘贴改代码吗,还占空间对不对。
那么咱们写一我的类,毕竟好人和坏人都是人:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Person(object): 5 6 def __init__(self, gun, grenade, blood): 7 self.gun = gun 8 self.grenade = grenade 9 self.blood = blood 10 11 def fire(self, person): 12 person.blood -= 5 13 self.gun.shoot() 14 print(str(person) + "血量减小5,剩余" + str(person.blood) ) 15 16 def fire2(self, person): 17 person.blood -= 10 18 self.grenade.damage() 19 print(str(person) + "血量减小10,剩余" + str(person.blood) ) 20 21 def fillbullet(self): 22 self.gun.bulletbox.bulletcount += 10 23 24 def fillblood(self,num): 25 self.blood += num 26 if self.blood > 100: 27 self.blood = 100 28 print(str(self) + "补血后血量:" + str(self.blood))
如今咱们就没必要把好人坏人都重写了,只须要继承一下人类就行了:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 from cs.person import Person 5 6 class Profector(Person): 7 8 def __init__(self, gun, grenade, blood = 100): 9 super(Profector,self).__init__(gun, grenade, blood) 10 11 12 class Gengster(Person): 13 14 def __init__(self, gun, grenade, blood=100): 15 super(Gengster, self).__init__(gun, grenade, blood) 16 17 # 这里面有个supper,他就是对父类的继承
我知道你们看的有点迷了,我把他整在一块儿了,不过仍是建议你们先根据每一个小模块学习,顺便理解一下引入自定义模块。下面是完整代码,能够直接粘贴:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 class Bulletbox(object): 5 def __init__(self,bulletcount): 6 self.bulletcount = bulletcount 7 8 9 class Gun(object): 10 def __init__(self,bulletbox): 11 self.bulletbox = bulletbox 12 13 def shoot(self): 14 if self.bulletbox.bulletcount == 0: 15 print('没子弹了') 16 else: 17 self.bulletbox.bulletcount -= 1 18 print(str(self) + '开一枪,还剩%d颗子弹' % (self.bulletbox.bulletcount)) 19 20 21 class Grenade(object): 22 def __init__(self,grenadecount): 23 self.grenadecount = grenadecount 24 25 def damage(self): 26 if self.grenadecount == 0: 27 print('手雷没有了') 28 else: 29 self.grenadecount -= 1 30 print(str(self) + "轰他一炮,手雷还剩%d颗" % (self.grenadecount)) 31 32 33 class Person(object): 34 def __init__(self, gun, grenade, blood): 35 self.gun = gun 36 self.grenade = grenade 37 self.blood = blood 38 39 def fire(self, person): 40 person.blood -= 5 41 self.gun.shoot() 42 print(str(person) + "血量减小5,剩余" + str(person.blood) ) 43 44 def fire2(self, person): 45 person.blood -= 10 46 self.grenade.damage() 47 print(str(person) + "血量减小10,剩余" + str(person.blood) ) 48 49 def fillbullet(self): 50 self.gun.bulletbox.bulletcount += 10 51 52 def fillblood(self,num): 53 self.blood += num 54 if self.blood > 100: 55 self.blood = 100 56 print(str(self) + "补血后血量:" + str(self.blood)) 57 58 59 class Profector(Person): 60 def __init__(self, gun, grenade, blood = 100): 61 super(Profector,self).__init__(gun, grenade, blood) 62 63 64 class Gengster(Person): 65 def __init__(self, gun, grenade, blood=100): 66 super(Gengster, self).__init__(gun, grenade, blood) 67 68 69 bulletbox = Bulletbox(10) 70 gun = Gun(bulletbox) 71 grenade = Grenade(20) 72 73 good1 = Profector(gun,grenade) 74 good2 = Profector(gun,grenade) 75 bad1 = Gengster(gun,grenade) 76 bad2 = Gengster(gun,grenade) 77 78 print("好人1开枪打坏人1和2") 79 good1.fire(bad1) 80 good1.fire(bad2) 81 print("好人2开枪打坏人1和2") 82 good2.fire(bad1) 83 good2.fire(bad2) 84 print("坏人1炸好人1和2") 85 bad1.fire2(good1) 86 bad1.fire2(good2) 87 print("坏人2炸好人1和2") 88 bad2.fire2(good1) 89 bad2.fire2(good2) 90 print("坏人1补血3个") 91 bad1.fillblood(3)
我在这里还想和你们一块儿看一下结果:
看一下有没有发现什么问题呢?
血量减小的人的对象仍是正常的,然而看一下开枪的人。有没有发现好人1和好人2的对象时同一个地址呢,他们的子弹也是累积的递减;坏人使用手榴弹也是。为何开枪的人会是这样,而受伤的人倒是正常的呢?
提醒一下,咱们前面建立的那些对象,有些是为了下一个对象调用而准备的,看看出错是在那个模块里错的,出错的和正确的他们之间有哪些不同呢,并且出错的原理是什么呢?你们能够思考思考,评论区互相讨论一下。
今天就到这里了,你们多多互动,互相学习。但愿路过的大佬指点指点。