Python学习笔记——基础篇第六周——面向对象
Posted Yared
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习笔记——基础篇第六周——面向对象相关的知识,希望对你有一定的参考价值。
Python之路,Day6 - 面向对象学习
- 写重复代码是非常不好的低级行为
- 你写的代码需要经常变更
#role 1 name = \'Alex\' role = \'terrorist\' weapon = \'AK47\' life_value = 100 #rolw 2 name2 = \'Jack\' role2 = \'police\' weapon2 = \'B22\' life_value2 = 100
上面定义了一个恐怖份子Alex和一个警察Jack,但只2个人不好玩呀,一干就死了,没意思,那我们再分别一个恐怖分子和警察吧,
#role 1 name = \'Alex\' role = \'terrorist\' weapon = \'AK47\' life_value = 100 money = 10000 #rolw 2 name2 = \'Jack\' role2 = \'police\' weapon2 = \'B22\' life_value2 = 100 money2 = 10000 #role 3 name3 = \'Rain\' role3 = \'terrorist\' weapon3 = \'C33\' life_value3 = 100 money3 = 10000 #rolw 4 name4 = \'Eric\' role4 = \'police\' weapon4 = \'B51\' life_value4 = 100 money4 = 10000
roles = { 1:{\'name\':\'Alex\', \'role\':\'terrorist\', \'weapon\':\'AK47\', \'life_value\': 100, \'money\': 15000, }, 2:{\'name\':\'Jack\', \'role\':\'police\', \'weapon\':\'B22\', \'life_value\': 100, \'money\': 15000, }, 3:{\'name\':\'Rain\', \'role\':\'terrorist\', \'weapon\':\'C33\', \'life_value\': 100, \'money\': 15000, }, 4:{\'name\':\'Eirc\', \'role\':\'police\', \'weapon\':\'B51\', \'life_value\': 100, \'money\': 15000, }, } print(roles[1]) #Alex print(roles[2]) #Jack
- 被打中后就会掉血的功能
- 开枪功能
- 换子弹
- 买枪
- 跑、走、跳、下蹲等动作
- 保护人质(仅适用于警察)
- 不能杀同伴
- 。。。
def shot(by_who): #开了枪后要减子弹数 pass def got_shot(who): #中枪后要减血 who[‘life_value’] -= 10 pass def buy_gun(who,gun_name): #检查钱够不够,买了枪后要扣钱 pass ...
- 每个角色定义的属性名称是一样的,但这种命名规则是我们自己约定的,从程序上来讲,并没有进行属性合法性检测,也就是说role 1定义的代表武器的属性是weapon, role 2 ,3,4也是一样的,不过如果我在新增一个角色时不小心把weapon 写成了wepon , 这个程序本身是检测 不到的
- terrorist 和police这2个角色有些功能是不同的,比如police是不能杀人质的,但是terrorist可能,随着这个游戏开发的更复杂,我们会发现这2个 角色后续有更多的不同之处, 但现在的这种写法,我们是没办法 把这2个角色适用的功能区分开来的,也就是说,每个角色都可以直接调用任意功能,没有任何限制。
- 我们在上面定义了got_shot()后要减血,也就是说减血这个动作是应该通过被击中这个事件来引起的,我们调用 get_shot(),got_shot()这个函数再调用每个角色里的life_value变量来减血。 但其实我不通过got_shot(),直接调用角色roles[role_id][‘life_value’] 减血也可以呀,但是如果这样调用的话,那可以就是简单粗暴啦,因为减血之前其它还应该判断此角色是否穿了防弹衣等,如果穿了的话,伤害值肯定要减 少,got_shot()函数里就做了这样的检测,你这里直接绕过的话,程序就乱了。 因此这里应该设计 成除了通过got_shot(),其它的方式是没有办法给角色减血的,不过在上面的程序设计里,是没有办法实现的。
- 现在需要给所有角色添加一个可以穿防弹衣的功能,那很显然你得在每个角色里放一个属性来存储此角色是否穿 了防弹衣,那就要更改每个角色的代码,给添加一个新属性,这样太low了,不符合代码可复用的原则
class Role(object): def __init__(self,name,role,weapon,life_value=100,money=15000): self.name = name self.role = role self.weapon = weapon self.life_value = life_value self.money = money def shot(self): print("shooting...") def got_shot(self): print("ah...,I got shot...") def buy_gun(self,gun_name): print("just bought %s" %gun_name) r1 = Role(\'Alex\',\'police\',\'AK47’) #生成一个角色 r2 = Role(\'Jack\',\'terrorist\',\'B22’) #生成一个角色
- 代码量少了近一半
- 角色和它所具有的功能可以一目了然看出来
class Role(object): #定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法,必须这样写,以后再讲为什么 def __init__(self,name,role,weapon,life_value=100,money=15000): #初始化函数,在生成一个角色时要初始化的一些属性就填写在这里 self.name = name #__init__中的第一个参数self,和这里的self都 是什么意思? 看下面解释 self.role = role self.weapon = weapon self.life_value = life_value self.money = money
r1 = Role(\'Alex\',\'police\',\'AK47’) #生成一个角色 , 会自动把参数传给Role下面的__init__(...)方法 r2 = Role(\'Jack\',\'terrorist\',\'B22’) #生成一个角色
r1 = Role(\'Alex\',\'police\',\'AK47’) #此时self 相当于 r1 , Role(r1,\'Alex\',\'police\',\'AK47’) r2 = Role(\'Jack\',\'terrorist\',\'B22’)#此时self 相当于 r2, Role(r2,\'Jack\',\'terrorist\',\'B22’)
- 在内存中开辟一块空间指向r1这个变量名
- 调用Role这个类并执行其中的__init__(…)方法,相当于Role.__init__(r1,\'Alex\',\'police\',’AK47’),这么做是为什么呢? 是为了把\'Alex\',\'police\',’AK47’这3个值跟刚开辟的r1关联起来,是为了把\'Alex\',\'police\',’AK47’这3个值跟刚开辟的r1关联起来,是为了把\'Alex\',\'police\',’AK47’ 这3个值跟刚开辟的r1关联起来,重要的事情说3次, 因为关联起来后,你就可以直接r1.name, r1.weapon 这样来调用啦。所以,为实现这种关联,在调用__init__方法时,就必须把r1这个变量也传进去,否则__init__不知道要把那3个参数跟谁关联 呀。
- 明白了么哥?所以这个__init__(…)方法里的,self.name = name , self.role = role 等等的意思就是要把这几个值 存到r1的内存空间里。
def buy_gun(self,gun_name): print(“%s has just bought %s” %(self.name,gun_name) )
上面这个方法通过类调用的话要写成如下:
r1 = Role(\'Alex\',\'police\',\'AK47\') r1.buy_gun("B21”) #python 会自动帮你转成 Role.buy_gun(r1,”B21")
- 上面的这个r1 = Role(\'Alex\',\'police\',\'AK47’)动作,叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了, 这个对象就叫做实例
- 刚才定义的这个类体现了面向对象的第一个基本特性,封装,其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容
面向对象的特性:
封装
封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。
OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
1 #!_*_coding:utf-8_*_ 2 #__author__:"Alex Li" 3 4 5 6 class SchoolMember(object): 7 members = 0 #初始学校人数为0 8 def __init__(self,name,age): 9 self.name = name 10 self.age = age 11 12 def tell(self): 13 pass 14 15 def enroll(self): 16 \'\'\'注册\'\'\' 17 SchoolMember.members +=1 18 print("\\033[32;1mnew member [%s] is enrolled,now there are [%s] members.\\033[0m " %(self.name,SchoolMember.members)) 19 20 def __del__(self): 21 \'\'\'析构方法\'\'\' 22 print("\\033[31;1mmember [%s] is dead!\\033[0m" %self.name) 23 class Teacher(SchoolMember): 24 def __init__(self,name,age,course,salary): 25 super(Teacher,self).__init__(name,age) 26 self.course = course 27 self.salary = salary 28 self.enroll() 29 30 31 def teaching(self): 32 \'\'\'讲课方法\'\'\' 33 print("Teacher [%s] is teaching [%s] for class [%s]" %(self.name,self.course,\'s12\')) 34 35 def tell(self): 36 \'\'\'自我介绍方法\'\'\' 37 msg = \'\'\'Hi, my name is [%s], works for [%s] as a [%s] teacher !\'\'\' %(self.name,\'Oldboy\', self.course) 38 print(msg) 39 40 class Student(SchoolMember): 41 def __init__(self, name,age,grade,sid): 42 super(Student,self).__init__(name,age) 43 self.grade = grade 44 self.sid = sid 45 self.enroll() 46 47 48 def tell(self): 49 \'\'\'自我介绍方法\'\'\' 50 msg = \'\'\'Hi, my name is [%s], I\'m studying [%s] in [%s]!\'\'\' %(self.name, self.grade,\'Oldboy\') 51 print(msg) 52 53 if __name__ == \'__main__\': 54 t1 = Teacher("Alex",22,\'Python\',20000) 55 t2 = Teacher("TengLan",29,\'Linux\',3000) 56 57 s1 = Student("Qinghua", 24,"Python S12",1483) 58 s2 = Student("SanJiang", 26,"Python S12",1484) 59 60 t1.teaching() 61 t2.teaching() 62 t1.tell()
多态
class Animal: def __init__(self, name): # Constructor of the class self.name = name def talk(self): # Abstract method, defined by convention only raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): return \'Meow!\' class Dog(Animal): def talk(self): return \'Woof! Woof!\' animals = [Cat(\'Missy\'), Dog(\'Lassie\')] for animal in animals: print animal.name + \': \' + animal.talk()
以上是关于Python学习笔记——基础篇第六周——面向对象的主要内容,如果未能解决你的问题,请参考以下文章
Python学习笔记——基础篇第六周——Subprocess模块