一、常用术语
1、抽象
2、封装/接口
3、合成
4、派生/继承/继承结构
5、泛化/特化
6、多态
7、自省/反射
二、引言
1、假设你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎么描述这种不同的角色和他们的功能呢?
def person(name,age,sex,job): data = { 'name':name, 'age':age, 'sex':sex, 'job':job } return data def dog(name,dog_type): data = { 'name':name, 'type':dog_type } return data
上面的两个方法相当于创造了两个模子,游戏里的每个人和狗都拥有相同的属性,游戏开始,你根据一个人或一只狗传入的具体信息来塑造一个人或一条狗
传入具体信息来塑造一个具体的人或狗
生成:
d1 = dog("李磊","京巴") p1 = person("严帅",36,"F","运维") p2 = person("egon",27,"F","Teacher") 两个角色对象生成了,狗和人还有不同的功能呀,狗会咬人,人会打狗,对不对? 怎么实现呢,。。想到了, 可以每个功能再写一个函数,想执行哪个功能,直接 调用 就可以了, d1 = dog("李磊","京巴") p1 = person("严帅",36,"F","运维") p2 = person("egon",27,"F","Teacher") #调用方法 walk(p1) bark(d1) #但因为操作失误 p1 = person("严帅",36,"F","运维") bark(p1) #把人的对象传给了狗的方法
从代码上来看,这并没出错。但很显然,人是不能调用狗的功能的,但在你的程序例没有做限制
修改后的代码:
def person(name, age, sex, job): def walk(p): print("person %s is walking..." % p['name']) data = { 'name': name, 'age': age, 'sex': sex, 'job': job, 'walk': walk } return data def dog(name, dog_type): def bark(d): print("dog %s:wang.wang..wang..." % d['name']) data = { 'name': name, 'type': dog_type, 'bark': bark } return data d1 = dog("李磊", "京巴") p1 = person("严帅", 36, "F", "运维") p2 = person("egon", 27, "F", "Teacher")
这种编程思想其实就是简单的面向对象编程,我们创造了两个模子表示游戏里所有的人和狗之后,剩下的狗叫或者人走对于这两个模子来说就不重要了。具体人和狗之间的交互就等着你去使用了。假如你和狗打起来了,这时候你是走路还是拿棍子打狗就由你自己决定了。
三、 面向对象vs面向过程
面向过程:
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
面向对象:
优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
四、初识类和对象
python中一切皆为对象,类型的本质就是类
dict #类型dict就是类dict
<class 'dict'>
>>> d=dict(name='eva') #实例化
>>> d.pop('name') #向d发一条消息,执行d的方法pop
'eva'
五、类的相关知识
1、初始类
1)声明函数:
def functionName(args):
'函数文档字符串'
函数体
2)声明类
'''
class 类名:
'类的文档字符串'
类体
'''
#我们创建一个类
class Data: pass
class Person: #定义一个人类
role = 'person'
#人的角色属性都是人
def walk(self):
#人都可以走路,也就是有一个走路方法,也叫动态属性
print("person is walking...")
2、类的两种作用:属性引用和实例化
1)属性引用(类名.属性)
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用 2)实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用来为每个实例定制自己的特性 class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def __init__(self,name): self.name = name # 每一个角色都有自己的昵称; def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") print(Person.role) #查看人的role属性 print(Person.walk) #引用人的走路方法,注意,这里不是在调用 实例化的过程就是类 —- > 对象的过程 egg = Person(‘egon’)
3)查看属性&调用方法
Print(egg.name)
Print(egg.walk())
4)关于self
在实例化是自动将对象/实例本身传给__init__的第一个参数,
5)类属性补充
(1)定义的类的属性到底存到了哪里?
dir(类名):查出的是一个字典,key为属性名,value为属性值
(2)特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
六、对象的相关知识
1、对象是关于类而实际存在的一个例子,即实例
2、对象/实例只有一种作用:属性引用
class Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name, aggressivity, life_value): self.name = name # 每一个角色都有自己的昵称; self.aggressivity=aggressivity # 每一个角色都有自己的攻击力; self.life_value = life_value # 每一个角色都有自己的生命值; def attack(self,dog): # 人可以攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 dog.life_value -= self.aggressivity egg = Person('egon',10,1000) print(egg.name) print(egg.aggressivity) print(egg.life_value)
七、对象之间的交互
1、人狗大战完整代码:
class Dog: # 定义一个狗类 role = 'dog' # 狗的角色属性都是狗 def __init__(self, name, breed, aggressivity, life_value): self.name = name # 每一只狗都有自己的昵称; self.breed = breed # 每一只狗都有自己的品种; self.aggressivity = aggressivity # 每一只狗都有自己的攻击力; self.life_value = life_value # 每一只狗都有自己的生命值; def bite(self,people): # 狗可以咬人,这里的狗也是一个对象。 # 狗咬人,那么人的生命值就会根据狗的攻击力而下降 people.life_value -= self.aggressivity egg = Person('egon',10,1000) #创造了一个实实在在的人egg ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 print(ha2.life_value) #看看ha2的生命值 egg.attack(ha2) #egg打了ha2一下 print(ha2.life_value) #ha2掉了10点血
2、圆的类:
from math import pi class Circle: ''' 定义了一个圆形类; 提供计算面积(area)和周长(perimeter)的方法 ''' def __init__(self,radius): self.radius = radius def area(self): return pi * self.radius * self.radius def perimeter(self): return 2 * pi *self.radius circle = Circle(10) #实例化一个圆 area1 = circle.area() #计算圆面积 per1 = circle.perimeter() #计算圆周长 print(area1,per1) #打印圆面积和周长
八、面对对象的组合用法
1、组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Weapon: def prick(self, obj): # 这是该装备的主动技能,扎死对方 obj.life_value -= 500 # 假设攻击力是500 class Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name): self.name = name # 每一个角色都有自己的昵称; self.weapon = Weapon() # 给角色绑定一个武器; egg = Person('egon') egg.weapon.prick() #egg组合了一个武器的对象,可以直接egg.weapon来使用组合类中的所有方法
九、小结
class Animal: def __init__(self,name,aggr,hp): self.name = name self.aggr = aggr self.hp = hp def eat(self): print('回血') self.hp += 100 class Person(Animal): def __init__(self,name,aggr,hp,sex): Animal.__init__(self,name,aggr,hp) self.sex = sex self.money = 0 def attack(self,dog): dog.hp -= self.aggr print(dog.hp) def get_weapon(self,weapon): if self.money >= weapon.price: self.money -=weapon.price self.weapon = weapon self.aggr += weapon.aggr else: print('余额不足') class Dog(Animal): def __init__(self,name,aggr,hp,kind): Animal.__init__(self,name,aggr,hp) self.kind = kind #派生属性 def attack(self,person): person.hp -= self.aggr print(person.hp) def eat(self): Animal.eat(self) self.aggr += 2 class Weapon: def __init__(self,name,aggr,njd,price): self.name = name self.aggr = aggr self.njd = njd self.price = price def hand18(self,person): if self.njd > 0: person.hp -= self.aggr*2 self.njd -= 1 alex = Person('jin',10,500,'nan') dog = Dog('jin',10,500,'gong') print(dog.name) print(dog.hp) print(dog.aggr) dog.eat() print(dog.hp) print(dog.aggr)