人狗对战小游戏
1.描述人与狗:描述人与狗的方式:使用字典一个个描述
dog 1 = { 'name':'小黑', 'type':'田园犬', 'attack_val':30, 'life_val':200 } dog 2 = { 'name':'小白', 'type':'恶霸犬', 'attack_val':180, 'life_val':500 } person 1 = { 'name': '小龙', 'type':'猛男', 'attack_val':10, 'life_val':1000 }
2.这样反复写很麻烦 :我们可以封装成函数 减少代码冗余 所以要定义专门用来描述人与狗的函数(最好单独编写)
def get_person(name, gender, age, t_type, attack_val, life_val): data_dict = { # 'name': name, # 'gender': gender, # 'age': age, # 't_type': t_type, # 'attack_val': attack_val, # 'life_val': life_val # } return data_dict # p1 = get_person('jason', 'male', 18, '猛男', 800, 1000) # p2 = get_person('kevin', 'female', 28, '淑女', 5, 100) # dog1 = get_dog('小黑', '松狮犬', 300, 500) # dog2 = get_dog('小白', '泰迪犬', 50, 200) # def dog_attack(dog_obj, person_obj): # """ # :param dog_obj: 接收一条狗 # :param person_obj: 接收一个人
3.使用最简单的掉血逻辑 血量减去对方攻击力
print('当前人的血量是:%s' % person_obj.get('life_val')) # person_obj['life_val'] -= dog_obj.get('attack_val') # print("""狗:%s 咬了人:%s 一口 人掉血:%s 剩余血量:%s"""%(dog_obj.get('name'),person_obj.get('name'),dog_obj.get('attack_val'),person_obj['life_val'])) # def person_attack(person_obj, dog_obj): # """ # :param person_obj: 接收一个人 # :param dog_obj: 接收一条狗 # """ # print('当前狗的血量是:%s'%dog_obj.get('life_val')) # dog_obj['life_val'] -= person_obj.get('attack_val') # print("""人:%s 锤了狗:%s 一下 狗掉血:%s 剩余血量:%s"""%(person_obj.get('name'),dog_obj.get('name'),person_obj.get('attack_val'),dog_obj['life_val']))
4.在括号内调换参数 导致参数混乱 比如人使用狗的技能 狗使用人的技能
# 狗咬人 # dog_attack(dog2,p1) # print(p1) # 人锤狗 # person_attack(p2, dog1) # print(dog1) '''人调用了狗的攻击动作''' # dog_attack(p1, dog1) '''狗调用了人的攻击工作''' # person_attack(dog2,p2)
如何做到只有人可以调用人的攻击动作 狗调用狗的攻击动作
目的: 其实就是想让人的数据跟人的功能绑定 狗的数据跟狗的功能绑定
方法:将人的攻击动作功能放在产生人的函数数据内
def get_person(name, gender, age, t_type, attack_val, life_val): def person_attack(person_obj, dog_obj): :param person_obj: 接收一个人 :param dog_obj: 接收一条狗 print('当前狗的血量是:%s' % dog_obj.get('life_val')) dog_obj['life_val'] -= person_obj.get('attack_val') print("""人:%s 锤了狗:%s 一下 狗掉血:%s 剩余血量:%s""" % ( person_obj.get('name'), dog_obj.get('name'), person_obj.get('attack_val'), dog_obj['life_val'])) data_dict = { 'name': name, 'gender': gender, 'age': age, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val, 'person_attack':person_attack # 我们用人的功能来调用人的数据 } return data_dict def get_dog(name, t_type, attack_val, life_val): def dog_attack(dog_obj, person_obj): """ :param dog_obj: 接收一条狗 :param person_obj: 接收一个人 """ # 使用最简答的掉血逻辑 血量减去对方攻击力 print('当前人的血量是:%s' % person_obj.get('life_val')) person_obj['life_val'] -= dog_obj.get('attack_val') print("""狗:%s 咬了人:%s 一口 人掉血:%s 剩余血量:%s""" % ( dog_obj.get('name'), person_obj.get('name'), dog_obj.get('attack_val'), person_obj['life_val'])) data_dict = { 'name': name, 't_type': t_type, 'attack_val': attack_val, 'life_val': life_val, 'dog_attack':dog_attack # 我们用狗的攻击来调用狗的功能 } return data_dict
5.输入具体的数据 调用人的数据来调用人的功能 调用狗的数据来调用狗的功能 这样就不会造成数据与功能的混乱
p1 = get_person('jason','male',18,'猛男',800, 1000) p2 = get_person('kevin','female',28,'淑女',10,100) dog1 = get_dog('小黑', '松狮犬', 300, 500) dog2 = get_dog('小白', '泰迪犬', 50, 200) p1['person_attack'](p1,dog1) # person_attack(p1,dog1) dog1['dog_attack'](dog1,p2) #dog_attack(dog1,p2)
6.上述操作其实就是将数据与功能进行绑定
不再是所有的数据都可以调用任意的功能 造成数据与功能的混乱局面
上述将数据与功能整合到一起的操作其实就是 :面向对象编程的思想
1.面向过程编程
将程序的执行流程化 即分布操作 分布的过程中降低问题的复杂度 从而解决问题
例如:注册、登录、结算购物车...
注册:第一步获取用户名与密码
第二步比对用户名数据
..............结算:第一步获取购物车数据 第二步是计算金额与数量
过程可以理解成是流水线 面向过程编程可以理解成是在创建一条流水线
2.面向对象编程
核心就是"对象"二字
对象其实就是一个'容器',将数据与功能整合到一起
只要符合上述描述的事物都可以称之为是对象!!!
比如:人狗大战最后的函数内部含有数据与功能 可以称之为面向对象编程
模块文件内含有数据与功能 也可以称之为面向对象编程
综上:仔细想想会发现 在python中一切皆是对象!!!
python针对面向对象编程提供了专门的语法 识别度更高 编写更精简
例如:人、动物、游戏角色
面向过程与面向对象两者没有优劣之分 具体要结合实际情况
甚至在很多时候两者是混合在一起的 思想占据的比例不同而已
对象:数据与功能的结合体
类:即类别、种类、等价于诸多对象公有的特征(数据、功能)!!!
比如:在现实生活中
人 对象
一群人 人类
狗 对象
一群狗 犬类
上述中的人类 犬类是用来描述什么的?
就是用来描述多个对象'相同'特征的名词
比如:黄种人、黑种人、白种人都属于人类 但是彼此也有不同的特征
类只能描述出公共的特征!!! 不同的特征应该由对象自己描述
综上:类其实也是对象(数据与功能的结合体):一切皆对象
在代码编程中一般先有类再有对象
1.先定义类 后产生对象
学生类:
学生类公共的数据
学生类公共的功能
class Student: school = '清华大学' def choose_course(self): print('学生选课功能')
类体代码无需调用就会执行 会产生类的名称空间
类的语法结构
class 类名:
类体代码
1.class是定义类的关键字 类似于函数的def标志词
2.类名 类似于函数名 但是首字母需要大写 用于区分类与其他的区别
3.类体代码就是存放对象公共数据和功能的地方
公共数据:变量名 = 变量值
公共功能:函数
1查看类的名称空间的方法:双下dict
返回值是一个字典
print(Student.__dict__)
1.1 获取类的公共属性:双下dict[属性名]
类获取类公共的属性有一个简便的方式:采用句点符.
print(Student.__dict__['school']) print(Student.__dict__['choose_course']) # print(Student.school) print(Student.choose_course)
2.如何产生对象:类名加括号
2.1 类名加括号即可产生一个对象
obj1 = Student() obj2 = Student()
2.2 对象通过双下dict的结果:是一个空字典
print(obj1.__dict__, obj2.__dict__) # {} {}
2.3 对象通过点公共属性的结果:会拿到类的公共属性
类可以产生多个对象 然后每个对象可以直接拿到类中公共的属性
print(obj1.school) # 清华大学 # print(obj2.school) # 清华大学 # print(obj1.choose_course) # bound method # print(obj2.choose_course) # bound method
2.4 类名.公共属性 = '公共属性修改值' 可以修改名与值的对应关系
print(obj1.school) # 清华大学 print(obj2.school) # 清华大学 Student.school = '北京大学' Student.__dict__['school'] = '北京大学' 修改名字与值的对应关系 print(obj1.school) # 北京大学 print(obj2.school) # 北京大学
# 学生类 class Student: def __init__(self, name, age, gender): '''该方法就一个功能>>>:给对象添加独有的数据''' self.name = name # obj.__dict__['name'] = name self.age = age # obj.__dict__['age'] = age self.gender = gender # obj.__dict__['gender'] = gender # 学生类公共的数据 school = '清华大学' # 学生类公共的功能 def choose_course(self): print('学生选课功能') # obj1 = Student() # 空字典 目前对象没有自己独有的属性 # obj2 = Student() # 空字典 目前对象没有自己独有的属性 # print(obj1.__dict__) # 大白话就是给字典添加键值对 # print(obj2.__dict__) # 大白话就是给字典添加键值对 需求:要让每个对象都有自己的值 1.逐步给对象添加独有的数据 # obj1.__dict__['name'] = 'jason' # obj1.name = 'jason' # obj1.__dict__['age'] = 18 # obj1.age = 18 # obj1.__dict__['gender'] = 'male' # obj1.gender = 'male' # obj2.__dict__['name'] = 'kevin' # obj2.name = 'kevin' # obj2.__dict__['age'] = 2 # obj2.age = 28 # obj2.__dict__['gender'] = 'female' # obj2.gender = 'female' # print(obj1.__dict__,obj2.__dict__) # print(obj1.name) # jason # print(obj2.name) # kevin 2.经发现上述步骤,需要反复添加 所以将冗余的添加步骤封装成函数 # def init(obj,name,age,gender): # obj.name = name # obj.__dict__['name'] = name # obj.age = age # obj.__dict__['age'] = age # obj.gender = gender # obj.__dict__['gender'] = gender # init(obj1,'jason',18,'male') # init(obj2,'kevin',28,'female') # print(obj1.name) # print(obj2.name) 3.因上述数据并没有说明是哪个分类中适合该数据,可能是老师类,是动物类,学生类,还需要将上述的部分我们划分类给特定整合的类中去,所以我们要将上述进行包装放在类中 # obj1 = Student() # obj2 = Student() # Student.set_info(obj1,'jason',18,'male') # Student.set_info(obj2,'kevin',28,'female') # print(obj1.name) # jason # print(obj2.name) # kevin 4.类中针对给类中的对象创建独有数据的函数名 专门定义了一个固定的方法 利用类来给里面的对象来传对象中独有的参数 符合面向对象的精髓 # obj1 = Student('jason', 18, 'male') # obj2 = Student('kevin', 28, 'female') # print(obj1.__dict__) # print(obj2.__dict__) 类中的双下init方法会在类中产生对象的时候自动执行类中对象的具体步骤 1.先创建一个没有独有数据的空对象 2.将空对象和类的括号内传入的数据一并交给双下init执行 双下init的第一个参数就是对象本身 __init__(obj,name,age,gender) 3.将创建好的对象自动返回 目的是给我们能够减少代码的编写 针对括号内的第一个形参self其实就是一个普通的变量名而已 只不过该变量名将来专门接收对象用的 所以给它起了个固定的名字叫self
在类中定义的函数默认都是绑定给对象使用的
即对象来调 会自动将对象当做第一个参数传入
class Student: school = '清华大学' # __init__方法不要自己去调用 def __init__(self, name, age): self.name = name self.age = age def func(self): print('%s正在调用func方法'%self.name) def index(self): print('%s正在调用index方法'%self.name) obj1 = Student('jason', 18) # print(obj1) obj2 = Student('kevin', 28)
在调用类中函数 有几个参数就需要传几个参数
# Student.func(123,222)
对象调用类中函数 会将当前调用的对象当做第一个参数自动传入 故为啥能理解了为什么类中所有的函数第一个参数都是self
# obj1.func() # obj2.func() # print(obj1.func) # print(obj2.index)