【一】人狗大战小游戏引入
【1】游戏规则分析
-
人可以打狗,狗掉血,狗可以咬人,人掉血
-
人的属性
-
姓名
-
类型
-
年龄
-
攻击力
-
生命值
-
-
狗的属性
-
姓名
-
类型
-
年龄
-
攻击力
-
生命值
-
【二】封装成函数,减少代码冗余
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('knight', 'male', 22, '猛男', 50, 1000)
p2 = get_person('ddt', 'female', 24, '淑女', 10, 100)
dog1 = get_dog('小黑', '松狮犬', 30, 500)
dog2 = get_dog('小白', '泰迪犬', 10, 200)
p1['person_attack'](p1, dog1)
dog1['dog_attack'](dog1, p2)
(二)什么是面对对象
【1】面向对象理解
- 面向对象就相当于上帝,在上帝的视角,人是对象,动物是对象,石头是对象,水是对象,山是对象.....存在的可以扩充,不存在的可以创造。
【2】面向对象的优缺点
(1)面对对象的优点
-
解决程序的延展性
-
对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
(2)面向对象的缺点
-
编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。
- 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
-
无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。
- 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。
【3】什么是程序
-
程序=数据+功能
-
编写程序的本质就是定义一系列的数据,然后写出一些功能对数据进行操作
【三】类与对象
【1】什么是类
-
类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体
-
所以,先有鸡和先有蛋的问题就出来了
-
先有的一个个具体存在的对象(比如一个具体存在的人)
-
还是先有的人类这个概念,这个问题需要分两种情况去看
-
(1)现实中
-
在现实世界中:先有对象,再有类
-
世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念
-
也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在
(2)程序中
-
在程序中:务必保证先定义类,后产生对象
-
这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类
-
不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象
【四】面对对象编程
-
关键字 class 声明一个类
-
在类程序中,特征用变量名标识,功能用函数标识
-
因而在类中 函数名和变量名
【1】定义类
(1)类名 建议是驼峰体,例如:Student
-
方式一:class Student(object)
-
方式二:class Student()
-
方式三:class Student
class Student(object):
# 类名后面的()参数不写的话默认就是object
# object:父类
# 直接定义数据属性
school_name = "清华"
# 函数属性
def read(self):
age = 18
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
# 通过实例化得到一个对象
student = Student()
print(student) # <__main__.Student object at 0x000001399554FFD0>
# 想用类里面的属性和方法
print(student.school_name)
print(student.read())
【2】类的调用
(1)实例化类,得到对象
student_one = Student()
student_two = Student()
# 每一次得到的对象都是新的
print(id(student_one))
# 2274496937888
print(id(student_two))
# 2274496937696
(2)如何修改对象的属性
# 【1】通过类的名称空间修改属性
# 类的名称空间不允许修改属性
space_class = Student.__dict__
print(space_class, type(space_class)) # <class 'mappingproxy'>
# 这两种方式都可以获取
print(space_class['school_name'])
print(space_class.get('school_name'))
# 【2】修改对象的属性
class Student(object):
# 数据属性
school_name = '清华'
# 函数属性
def read(self):
age = 18
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
student = Student()
student_one= Student()
# 添加一个student字典,赋给obj_space
obj_space = student.__dict__
# 添加一个键为name,值为knight的键值对
obj_space['name'] = 'knight'
print(obj_space,type(obj_space)) # {'name': 'knight'} <class 'dict'>
print(obj_space['name']) # knight
# 输出里面定义过的学校名
print(student.school_name) # 清华
# 输出添加后的name值
print(student.name) # knight
# student_one是复制的student
print(student_one.school_name) # 清华
# 【3】批量修改属性
class Student(object):
# 数据属性
school_name = '清华'
# 函数属性
def read(self):
age = 18
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
student_one = Student()
student_two = Student()
# 方式一:通过名称空间字典替换
student_one.__dict__['name'] = 'knight'
# 方式二:通过 对象.属性名=属性值替换
# (1)逐个添加
student_one.name = 'knight'
student_one.age = 18
student_one.gender = 'male'
student_two.name = 'opp'
student_two.age = 19
student_two.gender = 'female'
print(student_one.name) # knight
print(student_one.age) # 18
print(student_one.gender) # male
# (2)批量向对象中添加各自独有的属性值和属性名
def init_obj(obj,name,age,gender):
obj.name = name
obj.age = age
obj.gender = gender
student_one = Student()
student_two = Student()
init_obj(obj=student_one,name='knight',age=18,gender='male')
print(student_one.name)
(3)在类内部初始化自己的参数
class Student(object):
# 数据属性
school_name = '清华'
def init_obj(self, name, age, gender): # 这个self就是类的对象本身
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
print(f"当前姓名是{self.name}")
print(f"当前年龄是{self.age}")
print(f"当前性别是{self.gender}")
student = Student()
# 给值,初始化
student.init_obj(name='knight',age=20,gender='male')
student.read()
(4)魔法方法值初始化方法 __init__
class Student(object):
# 数据属性
school_name = '清华'
def __init__(self, name, age, gend er): # 这个self就是类的对象本身
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
print(f"当前姓名是{self.name}")
print(f"当前年龄是{self.age}")
print(f"当前性别是{self.gender}")
# 给值,初始化
student = Student(name='knight',age=20,gender='male')
student.read()
# 需要再添加学生的信息
student_one = Student(name='hyt',age=22,gender='female')
student_one.read()
# 查看类的名称空间
print(student.__dict__) # {'name': 'knight', 'age': 20, 'gender': 'male'}
(5)属性查找顺序
class Student(object):
# 数据属性
school_name = '清华'
def __init__(self, name, age, gender): # 这个self就是类的对象本身
self.name = name
self.age = age
self.gender = gender
# 函数属性
def read(self):
# self:表示对象自己本身
print(f"当前学校是{self.school_name}")
print(f"当前姓名是{self.name}")
print(f"当前年龄是{self.age}")
print(f"当前性别是{self.gender}")
# 给值,初始化
student = Student(name='knight',age=20,gender='male')
print(student.name)
# 可以通过.覆盖原来的值
student.name = 'hyt' # student.__dict__['name'] = 'hyt'
print(student.name)
# 属性查找顺序
print(student.name)
print(student.school_name)
# 查找顺序
# 首先在自己的对象中查找
# 自己找不到就去父类里面找
# 父类没找到就去基类中找
# 如果基类里面也没有,就去object中找
# 否则报错
(6)列表特性回顾
num_one_list = [1, 2, 3, 4]
num_two_list = [5, 6, 7, 8]
num_one_list.append(9)
# 每一个列表都是一个单独的对象
print(num_one_list)
print(num_two_list)
class Student:
def __init__(self, name):
self.name = name
s1 = Student(name='knight')
print(id(s1))
s1.name = 'hyt'
print(id(s1))
【3】类的属性扩展
class Duck(Animal,object):
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
print(f"这是一一只鸭子叫{self.name}已经{self.age}岁了")
duck = Duck(name='tang', age=1)
# 属性介绍
# 【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__
# 【7】实例化得到对象