【一】人狗大战
【1】人狗大战小游戏描述
- 人可以打狗,狗掉血,狗可以咬人,人掉血
【2】人狗大战小游戏实现
(0)分析
- 人的属性
- 人的名字
- 人的类型
- 人的年龄
- 人的攻击力
- 人的生命值
- 狗的属性
- 狗的名字
- 狗的类型
- 狗的攻击值
- 狗的生命值
(1)定义人和狗的参数
- 方式一:使用字典定义属性
dog1 = {
'name': '小黑',
'type': '田园犬',
'attack_val': 30,
'life_val': 200
}
dog2 = {
'name': '小白',
'type': '恶霸犬',
'attack_val': 180,
'life_val': 500
}
person1 = {
'name': '小龙',
'type': '猛男',
'attack_val': 10,
'life_val': 1000
}
- 方式二:封装成函数,减少代码冗余
# 将人类的属性用函数声明
def get_person(name, gender, age, t_type, attack_val, life_val):
'''
:param name: 人的名字
:param gender: 人的性别
:param age: 人的年龄
:param t_type: 人的类型
:param attack_val: 攻击值
:param life_val: 生命值
:return:
'''
data_dict = {
'name': name,
'gender': gender,
'age': age,
't_type': t_type,
'attack_val': attack_val,
'life_val': life_val
}
return data_dict
# 将狗的属性用函数声明
def get_dog(name, t_type, attack_val, life_val):
'''
:param name: 狗的名字
:param t_type: 狗的类型
:param attack_val: 攻击值
:param life_val: 生命值
:return:
'''
data_dict = {
'name': name,
't_type': t_type,
'attack_val': attack_val,
'life_val': life_val
}
return data_dict
(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
def get_dog(name, t_type, attack_val, life_val):
data_dict = {
'name': name,
't_type': t_type,
'attack_val': attack_val,
'life_val': life_val
}
return data_dict
p1 = get_person('dream', 'male', 18, '猛男', 800, 1000)
p2 = get_person('hope', '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: 接收一个人
"""
# 使用最简答的掉血逻辑 血量减去对方攻击力
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']))
# 狗咬人
dog_attack(dog2, p1)
print(p1)
# 人锤狗
person_attack(p2, dog1)
print(dog1)
'''人调用了狗的攻击动作'''
dog_attack(p1, dog1)
'''狗调用了人的攻击工作'''
person_attack(dog2, p2)
【3】人狗大战小游戏优化
"""如何做到只有人可以调用人的攻击动作 狗调用狗的攻击动作"""
# 其实就是想让人的数据跟人的功能绑定 狗的数据跟狗的功能绑定
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
p1 = get_person('dream', 'male', 18, '猛男', 800, 1000)
p2 = get_person('hope', 'female', 28, '淑女', 10, 100)
dog1 = get_dog('小黑', '松狮犬', 300, 500)
dog2 = get_dog('小白', '泰迪犬', 50, 200)
p1['person_attack'](p1, dog1)
dog1['dog_attack'](dog1, p2)
【4】小结
- 上述操作其实就是将数据与功能进行绑定
- 不再是所有的数据都可以调用任意的功能
- 将上述数据与功能整合到一起的操作其实就是面向对象编程的思想
【二】什么是面向过程
【1】面向过程
- 关键就在于过程,意思就是将程序流程化
- 过程就是流水线,用到哪个功能就去写哪个功能。分步骤解决问题
- 过程指的是解决问题的步骤,即先干什么再干什么...
- 面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。
【2】优点
- 复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)
- 逻辑清晰
【3】缺点
- 一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
【三】什么是面向对象
【1】面向对象
- 面向过程,核心在于“对象”二字
- 对象的终极奥义就是将程序 “整合”
- 对象就是 “容器” ,用来盛放数据与功能
- 面向对象就相当于上帝,在上帝的视角,人是对象,动物是对象,石头是对象,水是对象,山是对象.....存在的可以扩充,不存咋的可以创造。
(1)面向对象设计
-
面向对象的设计就好比我们要设计一个小校园模拟器,我们需要在校园中创造各种生活场景,包括上课、做饭、打球等等。
-
这些场景对应的角色就是对象,比如老师、学生、运动员、厨师等。
-
而每一个角色都会对应其具有的责任和功能
- 比如一个学生具有姓名、年龄、性别、所在班级等。
- 学生还有能做的活动,读书、写作、跑步、打篮球等。
- 比如一个老师可以教书、批改作业等。
- 比如运行员可以参加训练和比赛等。
-
当我们的角色和功能构建好以后,我们又需要创建几个学生、一些老师和运行员,让他们进行各项活动。
- 比如一个学生可以上课、写作业、运动;
- 比如一个老师可以教课、批改作业;
- 比如一个运动员可以训练、参加比赛
【2】优缺点
(1)面向对象优点
- 解决了程序的扩展性。
- 对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
(2)面向对象缺点
- 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。
- 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
- 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。
- 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。
【四】类与对象
【零】什么是类
- 类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体
【1】类的属性
class Student(object):
# 数据属性
school_name = "清华"
# 函数属性
def read(self):
age = 18
# self : 表示对象自己本身,
print(f"当前学校是 {self.school_name}")
student = Student()
print(student) # <__main__.Student object at 0x000001F2074B1340>
# 想用类里面的属性和方法
print(student.school_name) # 清华
print(student.read())
# 当前学校是 清华
# None
【2】查看类的名称空间
print(Student.__dict__)
# # {'__module__': '__main__', 'school_name': '清华', 'read': <function Student.read at 0x000001906F653A30>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
【3】实例化类得到对象
# 得到的对象每一次都是新的
student_one = Student()
student_two = Student()
print(id(student_one))
# 1853725687376
print(id(student_two))
# 1853726139200
【4】如何修改对象的属性
(1)通过类的名称空间修改属性
[1]类的名称空间不允许修改属性
class Student(object):
# 数据属性
school_name = "清华"
# 函数属性
def read(self):
age = 18
# self : 表示对象自己本身,
print(f"当前学校是 {self.school_name}")
space_class = Student.__dict__
print(space_class, type(space_class)) # <class 'mappingproxy'>
print(space_class['school_name']) # 清华
print(space_class.get('school_name')) # 清华
Student.__dict__['school_name'] = '北大'
print(Student.__dict__['school_name']) #报错
(2)修改对象的属性
[1]通过类的名称空间修改属性
class DreamStudent(object):
school = '梦想学城'
def read_books(self):
print('is reading books')
def write_nodes(self):
print('is write nodes')
def running(self):
print('is running')
obj1 = DreamStudent() # 目前对象没有自己独有的属性
obj2 = DreamStudent() # 目前对象没有自己独有的属性
print(obj1.__dict__) # 大白话就是给字典添加键值对 {}
print(obj2.__dict__) # 大白话就是给字典添加键值对 {}
'''方案1:逐步给对象添加独有的数据'''
obj1.__dict__['name'] = 'chosen' # obj1.name = 'chosen'
obj1.__dict__['age'] = 18 # obj1.age = 18
obj1.__dict__['gender'] = 'male' # obj1.gender = 'male'
obj2.__dict__['name'] = 'hope' # obj2.name = 'hope'
obj2.__dict__['age'] = 2 # obj2.age = 2
obj2.__dict__['gender'] = 'female' # obj2.gender = 'female'
print(obj1.__dict__,
obj2.__dict__) # {'name': 'dream', 'age': 18, 'gender': 'male'} {'name': 'hope', 'age': 2, 'gender': 'female'}
print(obj1.name) # chosen
print(obj2.name) # hope
[2]封装成函数
class DreamStudent(object):
school = '梦想学城'
def read_books(self):
print('is reading books')
def write_nodes(self):
print('is write nodes')
def running(self):
print('is running')
obj1 = DreamStudent() # 目前对象没有自己独有的属性
obj2 = DreamStudent() # 目前对象没有自己独有的属性
print(obj1.__dict__) # 大白话就是给字典添加键值对 {}
print(obj2.__dict__) # 大白话就是给字典添加键值对 {}
'''方案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, 'chosen', 18, 'male')
init(obj2, 'hope', 28, 'female')
print(obj1.name)
print(obj2.name)
[3]封装成类的方法
class DreamStudent(object):
school = '梦想学城'
def read_books(self):
print('is reading books')
def write_nodes(self):
print('is write nodes')
def running(self):
print('is running')
def set_info(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
'''方案3:简单的封装成函数没有提现出面向对象整合的精髓>>>:将函数写到类中去'''
obj1 = DreamStudent()
obj2 = DreamStudent()
DreamStudent.set_info(obj1,'chosen',18,'male')
DreamStudent.set_info(obj2,'hope',28,'female')
print(obj1.name) # chosen
print(obj2.name) # hope
[4]类的魔法方法__init__
- 想在实例化的过程中就为三位学生定制各自独有的数据:
- 姓名,性别,年龄,需要我们在类内部新增一个
__init__
方法,如下
- 姓名,性别,年龄,需要我们在类内部新增一个
class DreamStudent(object):
school = '梦想学城'
# 该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def read_books(self):
print('%s is reading books' % self.name)
def write_nodes(self):
print('%s is write nodes' % self.name)
def running(self):
print('%s is running' % self.name)
def choose(self):
print('%s is choosing a course' % self.name)
- 然后重新实例出三位学生
s1 = DreamStudent('梦梦', '男', 18) # 先调用类产生空对象s1,然后调用DreamStudent.__init__(s1,'梦梦','男',18)
s2 = DreamStudent('萌萌', '女', 30)
s3 = DreamStudent('朦朦', '女', 20)
-
单拿stu1的产生过程来分析
-
调用类会先产生一个空对象stu1
-
然后将stu1连同调用类时括号内的参数一起传
DreamStudent.__init__(stu1,’梦梦’,’男’,18)
def __init__(self, name, sex, age):
self.name = name # stu1.name = '梦梦'
self.sex = sex # stu1.sex = '男'
self.age = age # stu1.age = 18
- 实例化类会产生对象的名称空间,同样可以用
__dict__
查看
class DreamStudent(object):
school = '梦想学城'
# 该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
def read_books(self):
print('%s is reading books' % self.name)
def write_nodes(self):
print('%s is write nodes' % self.name)
def running(self):
print('%s is running' % self.name)
def choose(self):
print('%s is choosing a course' % self.name)
stu1 = DreamStudent('梦梦', '男', 18)
print(stu1.__dict__)
# {'name': '梦梦', 'sex': '男', 'age': 18}
- 至此,我们造出了三个对象与一个类,对象存放各自独有的数据,类中存放对象们共有的内容
【5】属性查找顺序
class BaseStudent(object):
school_name = '北大'
class Student(BaseStudent):
# 数据属性
# school_name = "清华"
# 实例化对象的时候就会被触发 Student() 一定会报错
def __init__(self, name, age, gender):
# self 就是这个类的对象本身
self.name = name
self.age = age
self.gender = gender
def set_info(self,class_id):
self.class_id = class_id
# 函数属性
def read(self):
print(f"当前学校是 {self.school_name}")
print(f"当前学生姓名是 {self.name}")
print(f"当前学生年龄是 {self.age}")
print(f"当前学生性别是 {self.gender}")
print(f"当前学生课程ID是 {self.class_id}")
def write(self):
print(f"当前学生 :>>> {self.name} 可以写作业!")
# 初始化类得到对象
student = Student(name='dream', age=18, gender='male')
# print(student.name)
student.set_info(class_id=1)
student.read()
student.name = 'opp' # student.__dict__['name'] = 'opp'
print(student.name)
# 属性查找顺序
print(student.name)
print(student.school_name)
# 查找顺序
# 首先在自己的对象中查找
# 自己找不到就去父类里面找
# 如果父类里面找不到,就去基类里面找
# 如果基类里面也没有,就去 object 里面找
# 如果还是找不到则报错
【6】列表特性回顾
# 类型list就是类
print(type(list))
# <class 'type'>
# 实例化的到3个对象 list_one,list_two,list_three
list_one = list([1, 2, 3])
list_two = list(['a', 'b', 'c'])
list_three = list(['x', 'y'])
# 三个对象都有绑定方法append,是相同的功能,但内存地址不同
print(list_one.append)
# <built-in method append of list object at 0x0000022B219CDA80>
print(list_two.append)
# <built-in method append of list object at 0x0000022B21A0B880>
print(list_three.append)
# <built-in method append of list object at 0x0000022B21A16FC0>
# 操作绑定方法l1.append(4)
# 就是在往l1添加4,绝对不会将4添加到l2或l3
# 等同于list.append(list_one,4)
list_one.append(4)
print(list_one)
# [1, 2, 3, 4]
print(list_two)
# ['a', 'b', 'c']
print(list_three)
# ['x', 'y']
【五】类的属性扩展
# 【一】定义类
class Animal(object):
animal_name = ''
class Duck(Animal, object):
'''
这是一条注释
'''
# 这是一条注释
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
print(f"这是一只鸭子 叫 {self.name} 已经 {self.age} 岁了!")
def speak(obj):
print(f"obj.__class__.__name__ :>>>> {obj.__class__.__name__}")
duck = Duck(name='唐老鸭', age=2)
speak(obj=duck)
# 【二】属性介绍
# 【1】获取当前类的名字
print(Duck.__name__)
# 【2】获取类中的文档字符串
print(Duck.__doc__)
# 【3】获取类的父类
print(Duck.__base__) # <class '__main__.Animal'>
# 【4】获取类的所有父类
print(Duck.__bases__) # (<class '__main__.Animal'>, <class 'object'>)
# 【5】获取当前类的名称空间
print(Duck.__dict__)
# 【6】获取类定义所在的模块名
print(Duck.__module__) # __main__
标签:__,obj,name,val,对象,self,面向对象,面向,print
From: https://www.cnblogs.com/chosen-yn/p/18180807