类前戏
一、面向对象前夕
现在我们可以写个小小的游戏利用我们之前所学的所有知识
创建一个人狗大战首先我们要创建一个人和一条狗
推导1:
# 我们可以使用字典记录人的数据和狗的数据 person1 = { 'name': 'jason', 'p_type': '战士', 'attack': 200, 'life_avl': 1000 } dog1 = { 'name': '大黄', 'd_type': '泰迪', 'attack': 100, 'life_avl': 500 } ''' 这如果还想要这样写的话就会很麻烦,想要创建一个人就要重新编写,创建一条狗也一样 所以我们可以把这些数据封装成函数 '''
推导2:
def person(name, d_type, attack, life_avl): person1 = { 'name': name, 'p_type': d_type, 'attack': attack, 'life_avl': life_avl } return person1 # p1 = person('jason', '战士', 200, 2000) # print(p1) # {'name': 'jason', 'p_type': '战士', 'attack': 200, 'life_avl': 2000} # 这样我们就可以使用函数把一个人创建出来, 想要创建一个新的人直接调用函数即可 def dog(name, d_type, attack, life_avl): dog1 = { 'name': name, 'd_type': d_type, 'attack': attack, 'life_avl': life_avl } return dog1 # d1 = dog('大黄', '泰迪', 50, 500) # print(d1) # {'name': '大黄', 'd_type': '泰迪', 'attack': 50, 'life_avl': 500} # 这样会简便一点, 现在我们只要在创建一个人打狗的函数和一个狗咬人的函数即可 def person_attack(p1, d1): print('当前狗名称:%s, 当前狗的血量为:%s' % (d1.get('name'), d1.get('life_avl'))) d1['life_avl'] -= p1['attack'] print(f'人:{p1.get("name")} 打了狗:{d1.get("name")} ' f'狗掉了{p1.get("attack")} 狗剩余血量为:{d1.get("life_avl")}' ) def dog_attack(d1, p1): print('当前人的姓名:%s, 当前人的血量为:%s' % (p1.get('name'), p1.get('life_avl'))) p1['life_avl'] -= d1['attack'] print(f'狗:{d1.get("name")} 咬了人:{p1.get("name")} ' f'人掉了{p1.get("attack")} 人剩余血量为:{p1.get("life_avl")}' ) # 这样我们就可以潜玩一下了 我们首先创建角色 p1 = person('jason', 'male', 200, 2000) p2 = person('kevin', 'female', 100, 1000) d1 = dog('小黄狗', '大黄', 50, 500) d2 = dog('小黑狗', '大黑', 60, 600) # person_attack(p1, d1) ''' 当前狗名称:小黄狗, 当前狗的血量为:500 人:jason 打了狗:小黄狗 狗掉了200 狗剩余血量为:300 ''' # dog_attack(d2, p2) ''' 当前人的姓名:kevin, 当前人的血量为:1000 狗:小黑狗 咬了人:kevin 人掉了100 人剩余血量为:940
但是这样会出现一个小问题 '''
推导3:
# 到目前为止还是没有问题的 person_attack(d1, p1) ''' 当前狗名称:jason, 当前狗的血量为:2000 人:小黄狗 打了狗:jason 狗掉了50 狗剩余血量为:1950 ''' dog_attack(p1, d1) ''' 当前人的姓名:小黄狗, 当前人的血量为:500 狗:jason 咬了人:小黄狗 人掉了50 人剩余血量为:300 ''' ''' 这个时候人可以调用dog_attack的功能 而狗也可以调用person_attack 按理说person_attack只能给人用 dog_attack只能给狗 如果这样调的话就会乱套了 我们可以把产生人的数据和人的功能都放到一个函数中 狗的放到一起 ''' def person_obj(name, d_type, attack, life_avl): def person_attack(p1, d1): print('当前狗名称:%s, 当前狗的血量为:%s' % (d1.get('name'), d1.get('life_avl'))) d1['life_avl'] -= p1['attack'] print(f'人:{p1.get("name")} 打了狗:{d1.get("name")} ' f'狗掉了{p1.get("attack")} 狗剩余血量为:{d1.get("life_avl")}' ) person1 = { 'name': name, 'p_type': d_type, 'attack': attack, 'life_avl': life_avl, 'person_attack': person_attack } return person1 def dog_obj(name, d_type, attack, life_avl): def dog_attack(d1, p1): print('当前人的姓名:%s, 当前人的血量为:%s' % (p1.get('name'), p1.get('life_avl'))) p1['life_avl'] -= d1['attack'] print(f'狗:{d1.get("name")} 咬了人:{p1.get("name")} ' f'人掉了{p1.get("attack")} 人剩余血量为:{p1.get("life_avl")}' ) dog1 = { 'name': name, 'd_type': d_type, 'attack': attack, 'life_avl': life_avl, 'dog_attack': dog_attack } return dog1 # 这样我们就可以直接产生一个人的数据和功能 一条狗的数据和功能 p1 = person_obj('jason', 'male', 200, 2000) d1 = dog_obj('小黄', '小黄狗', 50, 500) p1.get('person_attack')(p1, d1) ''' 当前狗名称:小黄, 当前狗的血量为:500 人:jason 打了狗:小黄 狗掉了200 狗剩余血量为:300 这样人就可以绑定人的数据和人的功能 不会跟狗混合起来 ''' d1.get('dog_attack')(d1, p1) ''' 当前人的姓名:jason, 当前人的血量为:2000 狗:小黄 咬了人:jason 人掉了200 人剩余血量为:1950 狗亦是如此 '''
4.总结
将人的数据和人的功能绑定到一起
只有人可以调用人的功能
将狗的数据和狗的功能绑定到一起
只有狗可以调用狗的功能
我们把数据和功能绑定到一起的操作命名为>>>: 面向对象编程
本质: 将特定的功能和特定的数据绑定到一起 将来只能彼此互相使用
二、编程思想
面向过程编程: 截止之前我们全部编写的代码都是面向过程编程 过程就是流程 面向过程就是执行一系列的流程 eg:登入注册 添加购物车.... 就是按照指定的步骤依次执行 最终就可以得到想要的结果 面向对象编程: 核心就是'对象' 对象其实就是一个容器, 把数据和功能绑定到一起 eg:游戏人物 ... 我们就负责把人物创造出来 后续的战绩却不是我们能决定的 """ 面向过程编程相当于让你给出一个方案解决解决一个具体的问题 面向对象编程相当于让你创造一些事物后续不用你管了 """ 上述两种编程思想没有优劣之分 只有场景使用的不同 很多时候需要两种混用
三、对象与类的概念
对象:数据与功能的结合体 类:多个对象相同的数据和功能结合体 """ 我们可以这样理解: 一个人是一个对象 而多个人就会组成人类 一个人 对象 多个人 人类 人都有共同的特征:两个手、两条腿... 而每个人又都有自己的特征:说的语言不一样、人的肤色不一样... 一条狗 对象 多条狗 犬类 狗也有狗的共同特征:尾巴、四条腿走路... 而每条狗也有每条狗独有的特征:泰迪、藏獒... """ 类主要记录多个对象的共同数据和功能 对象主要记录多个对象不同的数据和功能
ps:在面向对象编程编写代码只是为了节省代码, 对象才是核心
四、对象与类的创建
''' 在现实生活中按理来说应该是一个一个个体(对象)组成一个群体(类) 而在编程中我们要先创建一个类才能创建对象 面向对象编程的本质就是将数据和功能绑定到一起 但是为了突出面向对象编程的的形式 python特地开发了一套语法专门用于面向对象编程的操作 ''' # 创建类的完整语法: ''' class Student: # 学生对象公共的功能 # 学生对象公共的数据 class: 是创建类的关键字 Student: 是类的名字 与变量名一致 推荐首字母大写(为了更好的区分) 类体代码: 共同的数据 共同的功能 ''' class Student: school = '清华大学' def choice_course(self): print('正在选课') # 如何查看类里的名字(名称空间) 我们可以使用双下dict方法 这个方法可以看到类的名称空间里的所有名字 print(Student.__dict__) # 可以看作是一个字典 ''' { '__module__': '__main__', 'school': '清华大学', 'choice_course': <function Student.choice_course at 0x000002FCE747DA60>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None } ''' # 我们可以使用字典的取值方法取出类里的数据 print(Student.__dict__['school']) # 清华大学 print(Student.__dict__.get('choice_course')) # <function Student.choice_course at 0x00000273FFB5DA60> # python为我们提供了跟简便的方法: 句点符取值 print(Student.school) # 清华大学 print(Student.choice_course) # <function Student.choice_course at 0x000002320A4CDA60> # 这种取值方法更上面的方法是相等的
五、实例化对象
''' 我们将类产生一个对象称之为实例化对象 ''' class Student: school = '清华大学' def choice_course(self): print('正在选课') # 类实例化产生对象>>>>:类名加括号 stu1 = Student() stu2 = Student() # 现在stu1和stu2就可以使用类中的数据和功能了 # print(stu1.school) # 清华大学 # print(stu1.choice_course) # <bound method Student.choice_course of <__main__.Student object at 0x000001B3A68AE1D0>> # print(stu2.school) # 清华大学 # print(stu2.choice_course) # <bound method Student.choice_course of <__main__.Student object at 0x0000014BC5369320>> ''' 我们可以发现stu1的choice_course和stu2的choice_course的内存地址不一样 因为产生stu1和stu2对象的时候肯定都是在内存地址中开不同的空间存放他们两个 ''' # print(stu1) # <__main__.Student object at 0x00000259C8B692B0> # print(stu2) # <__main__.Student object at 0x00000259C8B69320> # 我们可以查看stu1和stu2中内存空间的名字 # print(stu1.__dict__, stu2.__dict__) # {} {} # 我们发现是没有的因为我们还没有创建他们独有的数据 print(stu1.school) # 清华大学 print(stu2.school) # 清华大学 Student.school = '北京大学' print(stu1.school) # 北京大学 print(stu2.school) # 北京大学 # 我们可以通过类修改里面的值 # 我们通常把类或则对象句点符后面的的东西叫做属性名或则是方法名
六、对象独有的数据
推导1:
''' 我们可以通过类名加括号 来产生对象 那么我们怎么让对象有独有的数据呢 ''' class Student: school = '清华大学' def choice_course(self): print('正在选课') # 我们先产生几个对象: obj1 = Student() obj2 = Student() print(obj1.__dict__, obj2.__dict__) # {} {} # 现在stu1和stu2只有类中的共同的方法和数据本身没有任何数据 # 推导1: # 因为名称空间里可以看成是一个字典我们可以通过字典的方式给对象加值 obj1.__dict__['name'] = 'jason' obj1.__dict__['age'] = 18 obj1.__dict__['gender'] = 'male' print(obj1.name) # jason print(obj1.age) # 18 print(obj1.gender) # male print(obj1.school) # 清华大学 # 这样我们obj1对象就可以有属于自己的数据还可以调用类里的共同数据 obj2.__dict__['name'] = 'kevin' obj2.__dict__['age'] = 28 obj2.__dict__['gender'] = 'female' print(obj2.name) # kevin print(obj2.age) # 28 print(obj2.gender) # female print(obj2.school) # 清华大学 # obj2对象也有了自己的数据 自己只能调自己的数据 print(obj1.__dict__, obj2.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male'} {'name': 'kevin', 'age': 28, 'gender': 'female'} # 这样obj1和obj2名称空间中都有了自己的名字
推导2:
''' 但是这样如果每次创造一个对象的时候这样代码就会冗余而且复杂 我们可以把它封装成函数 ''' class Student: school = '清华大学' def choice_course(self): print('正在选课') # 我们先产生几个对象: def init(obj, name, age, gender): obj.__dict__['name'] = name obj.__dict__['age'] = age obj.__dict__['gender'] = gender stu1 = Student() stu2 = Student() init(stu1, 'jason', 18, 'male') init(stu2, 'kevin', 28, 'female') print(stu1.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male'} print(stu2.__dict__) # {'name': 'kevin', 'age': 28, 'gender': 'female'}
# 我们可以在定义函数的时候另一种写法
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
# 这样是其实跟上面那种完全一样只是简便了代码 stu1 = Student() stu2 = Student() init(stu1, 'jason', 18, 'male') init(stu2, 'kevin', 28, 'female') print(stu1.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male'} print(stu2.__dict__) # {'name': 'kevin', 'age': 28, 'gender': 'female'}
推导3:
''' 但是这样的话不是就任何人都可以调用这个函数了吗 这样老师可以调 医生可以调... 那就不是专门属于学生的数据了 所以我们要把这个函数封装到类里面, 这样只有学生类才可以调用这个数据 ''' class Student: 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 # 左右两边的名字虽然一样但是意义却不一样 左边相当于字典的键 右边相当于字典的值 school = '清华大学' def choice_course(self): print('正在选课') # 这样我们产生一个值的时候就会变成这样: stu1 = Student() print(stu1.__dict__) # {} 这个时候stu1是没有任何数据的 Student.init(stu1, 'jason', 18, 'male') # 我们要通过类给对象stu1产生数据 print(stu1.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male'} print(stu1.name) # jason 我们还可以通过句点符方法直接拿出字典中的值 # python知道这样写会麻烦所以给我们提供了关键字__init__ class Student: ''' __init__方法: 1.先产生一个空对象 2.自动调用类里面的__init__方法 将产生的空对象当成第一个参数闯入 3.然后在把产生的对象返回出去 ''' 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 # 左右两边的名字虽然一样但是意义却不一样 左边相当于字典的键 右边相当于字典的值 school = '清华大学' def choice_course(self): print('正在选课') # 这样我们在产生一个对象的的时候就会更简单了 stu1 = Student('jason', 18, 'male') # 产生对象时把stu1自动传入 print(stu1) # <__main__.Student object at 0x0000028674589470> print(stu1.__dict__) # {'name': 'jason', 'age': 18, 'gender': 'male'} print(stu1.name) # jason # 这样就可以省略代码量 更方便 __init__第一个参数其实我们应该写成self 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 choice_course(self): print('正在选课') stu1 = Student('jason', 18, 'male') print(stu1.__dict__) print(stu1.name) stu2 = Student('kevin', 28, 'female') print(stu2.__dict__) # {'name': 'kevin', 'age': 28, 'gender': 'female'} print(stu2.age) # 28 print(stu2.name) # kevin print(stu2.gender) # female print(stu2.school) # 清华大学 print(stu2.choice_course()) # 正在选课
总结
类能够有对象的共同数据和共同方法
类可以产生对象
对象有对象自己的数据
对象可以通过类调用类中共同的数据和方法