面向对象,面对对象编程,类与对象,双下init方法
1.面向对象前戏(猪狗争食从而引发战争—猪狗大战)
1.1编写猪和狗基本信息
1.2函数封装
1.3攻击能力
1.4正式干架
1.5莫名奇妙
1.6数据与功能绑定
2.面向编程
2.1面向过程编程
2.2面向对象编程
2.3面向过程和面向对象的区别
3.面向对象编程
3.1对象与类的概念
3.2类与对象的创建
3.3创建类的完整语法
3.3.1类和类名
3.3.2类的方法
3.3.3类的实例化产生对象
3.4__init__在类与对象中的应用
1.面向对象前戏(猪狗争食从而引发战争)
面向对象是什么,我也不知道,对于这个抽象的标题我们将通过下面的小游戏一起来研究面向对象究竟是什么,是做什么的。
1.1编写猪和狗基本信息
在编写这个之前我们要知道目前我们对于python的理解能编写储存信息的有字符串,字典,元组等,从中挑选最好的也莫过于字典了。
首先,我们先编写出两方阵营的一些基础信息:
狗猪基础信息
# 狗狗阵营
dog1 = {
'name': '小黑',
'blood_val': 100,
'attack_val': 20
}
dog2 = {
'name': '小白',
'blood_val': 300,
'attack_val': 30
}
# 猪猪阵营
pig1 = {
'name': '漂亮',
'blood_val': 200,
'attack_val': 10
}
pig2 = {
'name': '美丽',
'blood_val': 50,
'attack_val': 100
}
1.2函数封装
到这里,我们不免想到一个问题:像这样一个两个还好,但是,如果我们有一百个狗和一百个猪要打架的话,这些代码就会冗余,同时每个狗和猪的信息都会有些许相同的部分,结合之前的知识,我们可以将它们封装成函数,以传参的形式传值给函数内部:
狗狗阵营
def get_dog(name, blood_val, attack_val):
"""
专门用来产生用户的字典(创造狗狗)
:param name: 姓名
:param blood_val: 血量(生命值)
:param attack_val: 攻击力
:return: 狗狗的字典
"""
dog_obj = {
'name': name,
'blood_val': blood_val,
'attack_val': attack_val
}
return dog_obj
dog1 = get_dog('小黑', 300, 50)# 传参
dog2 = get_dog('小白', 100, 100) # 传参
print(dog1) # {'name': '小黑', 'blood_val': 300, 'attack_val': 50}
print(dog2) # {'name': '小白', 'blood_val': 100, 'attack_val': 100}
猪猪阵营
def get_pig(name, blood_val, attack_val):
"""
专门用来产生用户的字典(创造猪猪)
:param name: 姓名
:param blood_val: 血量(生命值)
:param attack_val: 攻击力
:return: 猪猪的字典
"""
pig_obj = {
'name': name,
'blood_val': blood_val,
'attack_val': attack_val
}
return pig_obj
pig1 = get_pig('翠花', 300, 50)# 传参
pig2 = get_pig('芙蓉', 100, 100) # 传参
print(pig1) # {'name': '翠花', 'blood_val': 200, 'attack_val': 50}
print(pig2) # {'name': '芙蓉', 'blood_val': 400, 'attack_val': 100}
1.3攻击能力
下面在对他们分别创建一个谁打谁的函数:
狗啃猪,猪啃狗代码
def dog_attack(dog_obj, pig_obj):
"""
专门用来提供给狗啃猪的
:param dog_obj: 传狗数据(字典)
:param pig_obj: 传猪数据(字典)
"""
# 先展示当前猪的状态
print('即将被啃的猪:%s 当前血量:%s' % (pig_obj.get('name'), pig_obj.get('blood_val')))
pig_obj['blood_val'] -= dog_obj.get('attack_val')
# 狗啃猪 直接用猪的生命值减去狗的攻击力
print('狗:%s 啃了 猪:%s 猪掉血:%s 剩余血量:%s' % (
dog_obj.get('name'), pig_obj.get('name'), pig_obj.get('attack_val'), pig_obj.get('blood_val')))
def pig_attack(pig_obj, dog_obj):
"""
专门用来提供给猪拱狗的
:param pig_obj: 猪的数据(子典)
:param dog_obj: 狗的数据(字典)
"""
# 先展示当前猪的状态
print('即将被拱的狗:%s 当前血量:%s' % (dog_obj.get('name'), dog_obj.get('blood_val')))
dog_obj['blood_val'] -= pig_obj.get('attack_val')
# 狗啃猪 直接用猪的生命值减去狗的攻击力
print('猪:%s 拱了 狗:%s 狗掉血:%s 剩余血量:%s' % (
pig_obj.get('name'), dog_obj.get('name'), dog_obj.get('attack_val'), dog_obj.get('blood_val')))
1.4正式干架
接着调用各自的函数展开攻击:
互相伤害
# 调用产生狗和猪的函数
dog1 = get_dog('小黑', 400, 50)
dog2 = get_dog('小白', 300, 100)
pig1 = get_pig('翠花', 200, 30)
pig2 = get_pig('如花', 50, 100)
# 调用攻击彼此的函数
pig_attack(pig1, dog1)
# 即将被拱的狗:小黑 当前血量:400
# 猪:翠花 拱了 狗:小黑 狗掉血:30 剩余血量:370
dog_attack(dog2, pig2)
# 即将被啃的猪:如花 当前血量:50
# 狗:小白 啃了 猪:如花 猪掉血:100 剩余血量:-50
1.5莫名奇妙
但是,在我们反复试用代码的时候发现,如果输入的位置不好就会产生如下的错误:
狗可以调用猪攻击的功能
猪可以调用狗攻击的功能
猪变成狗,狗变成猪
pig_attack(dog1, pig2)
# 即将被拱的狗:如花 当前血量:50
# 猪:小黑 拱了 狗:如花 狗掉血:50 剩余血量:0
dog_attack(pig2, dog2)
# 即将被啃的猪:小白 当前血量:300
# 狗:如花 啃了 猪:小白 猪掉血:100 剩余血量:200
1.6数据与功能绑定
所以,我们得进一步对代码进行优化(狗跟狗攻击猪的函数绑定 猪跟猪攻击狗的函数绑定)
狗跟狗的功能绑定 猪跟猪的功能绑定
def get_dog(name, blood_val, attack_val):
"""
专门用来产生用户的字典(创造狗狗)
:param name: 姓名
:param blood_val: 血量(生命值)
:param attack_val: 攻击力
:return: 狗狗的字典
"""
def dog_attack(dog_obj, pig_obj):
"""
专门用来提供给狗啃猪的
:param dog_obj: 传狗数据(字典)
:param pig_obj: 传猪数据(字典)
"""
# 先展示当前猪的状态
print('即将被啃的猪:%s 当前血量:%s' % (pig_obj.get('name'), pig_obj.get('blood_val')))
pig_obj['blood_val'] -= dog_obj.get('attack_val')
# 狗啃猪 直接用猪的生命值减去狗的攻击力
print('狗:%s 啃了 猪:%s 猪掉血:%s 剩余血量:%s' % (
dog_obj.get('name'), pig_obj.get('name'), dog_obj.get('attack_val'), pig_obj.get('blood_val')))
dog_obj = {
'name': name,
'blood_val': blood_val,
'attack_val': attack_val,
'dog_attack': dog_attack # 调用dog_attack
}
return dog_obj
def get_pig(name, blood_val, attack_val):
"""
专门用来产生用户的字典(创造猪猪)
:param name: 姓名
:param blood_val: 血量(生命值)
:param attack_val: 攻击力
:return: 猪猪的字典
"""
def pig_attack(pig_obj, dog_obj):
"""
专门用来提供给猪拱狗的
:param pig_obj: 猪的数据(子典)
:param dog_obj: 狗的数据(字典)
"""
# 先展示当前猪的状态
print('即将被拱的狗:%s 当前血量:%s' % (dog_obj.get('name'), dog_obj.get('blood_val')))
dog_obj['blood_val'] -= pig_obj.get('attack_val')
# 狗啃猪 直接用猪的生命值减去狗的攻击力
print('猪:%s 拱了 狗:%s 狗掉血:%s 剩余血量:%s' % (
pig_obj.get('name'), dog_obj.get('name'), pig_obj.get('attack_val'), dog_obj.get('blood_val')))
pig_obj = {
'name': name,
'blood_val': blood_val,
'attack_val': attack_val,
'pig_attack': pig_attack # 调用 pig_attack
}
return pig_obj
# 调用产生狗和猪的函数
dog1 = get_dog('小黑', 500, 50) # 创造出小黑
pig1 = get_pig('翠花', 400, 100) # 创造出翠花
dog1.get('dog_attack')(dog1, pig1)
# 即将被啃的猪:翠花 当前血量:400
# 狗:小黑 啃了 猪:翠花 猪掉血:50 剩余血量:350
上述操作其实就是将数据与功能进行绑定,不再是所有的数据都可以调用任意的功能,而这一操作其实就是面向对象的编程思想
2.面向编程
2.1面向过程编程
到目前为止,我们所学习的 注册功能, 登录功能... 都是面向过程编程,
过程就是流程,就是按照指定的步骤依次执行,最终得到想要的结果。
2.2面向对象编程
核心就是对象二字, 就像今天所做的猪狗大战游戏,我们只需要做出人物和功能,然后将他们绑定在一起,至于后续如何发展我们无需处理。
2.3面向过程和面向对象的区别
面向过程编程相当于让你给出一个问题的具体解决方案
面向对象编程相当于让你创造出一些事物之后不用你管
上述两种编程思想没有优劣之分 仅仅是使用场景不同
甚至很多时候是两者混合使用
3.面向对象编程
3.1对象与类的概念
什么是对象?什么是类?
| 对象 | 数据与功能的结合体 |
| 类 | 多个对象相同功能的结合体 |
对于对象和类我们可以这么理解:
我们把类比作一个工具箱,在工具箱中有很多种工具,工具箱的作用就是把这些工具的作用存放到一起,同时,他们又是彼此独立的一个对象(因为他们都有着自己独特的功能)

ps:
类主要用于记录多个对象相同的数据和功能
对象则用于记录多个对象不同的数据和功能
在面向对象编程中 类仅仅是用于节省代码 对象才是核心
3.2类与对象的创建
在今天的游戏代码编写中,我们首先触碰的是对象,然后才是类,同样在想是生活中我们对其的理解也是现有一个个的个体(对象),然后才会有群体(类)。但是在编程事件中必须要先有类才能产生对象
3.3创建类的完整语法
3.3.1 类和类名
class People:
class是定义类的关键字
People是类的名字
{类名的命名跟变量名一致 并且推荐首字母大写(为了更好的区分)}
ps:
类体代码在类定义阶段就会执行!!!
3.3.2 类的方法
1.类名.__dict__方法查看名称空间,获得的是一个字典
class Student:
# 学生对象公共的数据
school = '清华大学'
print(Student.__dict__) # 使用该方法查看名称空间 可以看成是一个字典
# {'__module__': '__main__', 'school': '清华大学', '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
2.类名.__dict__['字典的K键']查看字典的键值
class Student:
# 学生对象公共的数据
school = '清华大学'
print(Student.__dict__['school']) # 使用字典的取值方式获取名字
# 清华大学
3.类名.__dict__.get('公共的功能')使用字典的取值方式获取名字
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self): # 公共的功能(方法)
print('正在选课')
#print(Student.__dict__) # 使用该方法查看名称空间 可以看成是一个字典
print(Student.__dict__.get('choice_course')) # 使用字典的取值方式获取名字
# <function Student.choice_course at 0x000002B008CB80D0>
其实,在面向对象编程中 想要获取名称空间中的名字 可以采用句点符
类名.名称空间里面的K键
Student.school #清华大学
Student.choice_course #<function Student.choice_course at 0x000001C710D28790>
3.3.3 类的实例化产生对象
类名()
stu1 = Student()
stu2 = Student()
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self): # 公共的功能(方法)
print('正在选课')
stu1 = Student()
stu2 = Student()
print(stu1.school) #清华大学
print(stu2.school) #清华大学
对于对象也有自己的句点符方法,由于stu是Student类产生的对象,所以它内部的信息stu也可以访问的到
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self): # 公共的功能(方法)
print('正在选课')
print(stu1.__dict__, stu2.__dict__) # {} {} 查看stu1,stu2的名称空间(也是一个字典)
print(stu1.school) # 清华大学
print(stu2.school) # 清华大学
print(stu1.choice_course) # <bound method Student.choice_course of <__main__.Student object at 0x000001BBD5E04A30>>
print(stu2.choice_course) # <bound method Student.choice_course of <__main__.Student object at 0x000001BBD5E04A30>>
使用类的实例对象调用 __dict__,会输出由类中所有实例属性组成的字典
修改键值
类名.类中的数据名 = '给个值'
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self): # 公共的功能(方法)
print('正在选课')
print(stu1.school) # 北京大学
我们习惯将类或者对象句点符后面的东西称为属性名或者方法名
由于目前stu是Student类所产生的对象,所以stu能拿到的值只有Student的内部的值,如果我们想自己为stu添加值,就要用到对象特有的方法
我们来看:
1通过.__dict__['']的方法为子弹添加键值对
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self):
print('正在选课')
'''推导思路1: 直接利用__dict__方法朝字典添加键值对'''
obj1 = Student()
obj1.__dict__['name'] = 'jason' # 等价于 obj1.name = 'jason'
obj1.__dict__['age'] = 18 # 等价于 obj1.age = 18
obj1.__dict__['gender'] = 'male' # ...
print(obj1.name) # jason
print(obj1.age) # 18
print(obj1.gender) # male
print(obj1.school) # 清华大学
2 将添加独有数据的代码封装成函数
class Student:
# 学生对象公共的数据
school = '清华大学'
# 学生对象公共的方法
def choice_course(self):
print('正在选课')
'''推导思路2: 将添加独有数据的代码封装成函数'''
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__)
print(stu2.__dict__)
init函数是专用给学生对象创建独有的数据 其他对象不能调用>>>:面向对象思想 将数据和功能整合到一起
将函数封装到学生类中 这样只有学生类产生的对象才有资格访问
3__init__在类与对象中的应用
所以我们要将这一段函数添加到上面Student类中,这样只有学生才有资格访问,然后对代码进行更新(__init__,句点符)
__init__是你在定义类的时候将来产生的对象要有自己独有的一些数据使用的,并且__init__(self, name)里的self会自动当成对象
class Student:
"""
1.先产生一个空对象
2.自动调用类里面的__init__方法 将产生的空对象当成第一个参数传入
3.将产生的对象返回出去
"""
def __init__(self, name, age, gender): # def init(self, name, age, gender): 只能通过下面__dict__方法才能赋值,__init__更好
# 下面右边的都是老方法,句点符的方法更好用
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('正在选课')
# 因为用了def init(self, name, age, gender):,所以下面必须用__dict__
# stu1 = Student()
# print(stu1.__dict__)
# Student.init(stu1, 'jason', 18, 'male')
# print(stu1.__dict__)
# print(stu1.name)
# 直接在括号里面传参(因为用了__init__方法)
stu1 = Student('jason', 18, 'male')
print(stu1)
stu2 = Student('kevin', 28, 'female')
print(stu2)

浙公网安备 33010602011771号