Python基础之面向对象2(封装)
一、封装定义:
二、作用
三、私有成员:
1、基本概念及作用
2、__slots__手段私有成员:
3、@property属性手段私有成员:
四、基础示例代码
1、用方法封装变量
""" 练习:用方法封装变量 """ class Enemy: def __init__(self,name,atk,speed,hp): self.set_name(name) self.set_atk(atk) self.set_atk_speed(speed) self.set_hp(hp) def get_name(self): return self.__name def set_name(self,value): self.__name = value def get_atk(self): return self.__atk def set_atk(self, value): self.__atk = value def get_atk_speed(self): return self.__atk_speed def set_atk_speed(self, value): if 0 <= value <= 10: self.__atk_speed = value else: self.__atk_speed = 0 print("速度不再范围内,赋值失败") def get_hp(self): return self.__hp def set_hp(self, value): if 0 <= value <= 100: self.__hp = value else: self.__hp = 0 print("血量不再范围内,赋值失败") e01 = Enemy("zs",200,50,200) print(e01.get_name(),e01.get_hp(),e01.get_atk_speed())
2、用属性封装变量:
""" 练习:属性封装变量 """ class Enemy: def __init__(self, name, atk, speed, hp): self.name = name self.atk = atk self.speed = speed self.hp = hp @property def name(self): return self.__name @name.setter def name(self,value): self.__name = value @property def atk(self): return self.__atk @atk.setter def atk(self, value): self.__atk = value @property def speed(self): return self.__speed @speed.setter def speed(self, value): self.__speed = value @property def hp(self): return self.__hp @hp.setter def hp(self, value): self.__hp= value e01 = Enemy("zs", 200, 50, 200) print(e01.name, e01.hp, e01.speed)
3、基础代码1
""" 封装数据优势: 1.符合人类思考方式 2.将数据与对数据的操作封装起来。 使用方法封装变量 """ class Wife01: def __init__(self, name, age): self.name = name # 缺点:缺乏对象数据的封装,外界可以随意赋值. self.age = age w01 = Wife01("芳芳", 26) w02 = Wife01("铁锤", 86) w02.age = 87 # print(w02.age) # 注意:通过两个方法,读写私有变量. # 练习:定义敌人类(姓名,攻击力,攻击速度(0-10),血量(0--100)) class Wife02: def __init__(self, name = "", age = 0): self.set_name(name) # 私有成员:障眼法(解释器会改变双下划线开头的变量名) # self.__age = age self.set_age(age) def get_name(self): return self.__name def set_name(self,value): self.__name = value def get_age(self): return self.__age def set_age(self,value): if 20 <= value <= 30: self.__age = value else: print("我不要") w01 = Wife02("铁锤",86) # 找不到双下划线开头的数据 # print(w01.__age) # 通过下划线 + 类名 可以访问双下划线开头的数据 # print(w01._Wife02__age) w01.set_age(50) print(w01.get_age()) print(w01.__dict__)
4、基础代码2:
""" 使用属性封装变量 """ # 练习:修改Enemy类,使用属性封装变量 class Wife: def __init__(self, name="", age=0): self.name = name # 调用 @name.setter 修饰的方法 self.age = age # 调用 @age.setter 修饰的方法 @property # 拦截读取变量的操作 def name(self): # get_name() return self.__name @name.setter # 拦截写入变量的操作 def name(self, value): # set_name() self.__name = value @property def age(self): return self.__age @age.setter def age(self, value): if 20 <= value <= 30: self.__age = value else: self.__age = 0 print("我不要") w01 = Wife("铁锤", 86) print(w01.name) print(w01.age)
5、基础代码3:
""" __slots__ 属性 """ class SkillData: # 限制当前类,创建的对象,只能具有的实例变量. __slots__ = ("__name") def __init__(self, name): self.name = name @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value s01 = SkillData("技能名称") # s01.name = "降龙十八掌" print(s01.name) # 为当前对象,添加实例变量 # s01.time = 5 # print(s01.time) # print(s01.__dict__) # 因为使用了__slots__属性,所以不是使用__dict__.
6、基础代码4:
""" 需求: 老张开去车东北. 分而治之 -- 分解 变化点 练习:exercise01 """ #需求: 老张开去车东北. class Person: def __init__(self, name): self.name = name def go_to(self, type, str_pos): type.run(str_pos) class Car: def run(self, str_pos): print("行驶到", str_pos) p01 = Person("老张") c01 = Car() p01.go_to(c01, "东北")
五、实例练习:
练习1:
""" 以面向对象的思想,描述下列场景. 提示:对象与对象数据不同,类与类行为不同. 张三 教 李四 学习python 李四 教 张三 玩游戏 张三 工作 挣了8000元 李四 工作 挣了3000元 """ class Person: def __init__(self, name): # 人的姓名 self.name = name # 人会的所有技能 self.__skills = [] self.__total_money = 0 # 只读属性 @property def skills(self): # return self.__skills # 返回可变对象地址,意味着类外仍然可以操作可变对象 return self.__skills[:] # 返回新的可变对象地址,意味着类外仍然操作的是新可变对象,不影响原对象. # 备注:每次通过切片返回新对象,都会另外开辟空间创建新对象,占用过多内存. # 只读属性 @property def total_money(self): return self.__total_money @property def name(self): return self.__name @name.setter def name(self,value): self.__name = value def teach(self, person_other, str_skill): # person_other 的技能列表,增加str_skill person_other.__skills.append(str_skill) print(self.name, "教了", person_other.name, str_skill) def work(self, money): self.__total_money += money print(self.name, "工作挣了", money, "元") zs = Person("张三") ls = Person("李四") # 张三 教 李四 学习python zs.teach(ls, "python") # 李四 教 张三 玩游戏 ls.teach(zs, "游戏") zs.work(8000) ls.work(4000) #************************ zs = Person("张三") # zs.skills = [] # 不能改 # 如果skills属性,返回的是__skills,那么仍然可以操作私有列表 # __skills[:],那么操作的是新列表 zs.skills.append("python") print(zs.skills)
练习2:
""" 创建技能类(技能名称,冷却时间,持续时间,攻击距离......) 要求:使用属性封装变量 创建技能列表(技能对象的列表) -- 查找名称是"降龙十八掌"的技能对象 -- 查找名称是持续时间大于10秒的的所有技能对象 -- 查找攻击距离最远的技能对象 -- 按照持续时间,对列表升序排列. """ class SkillData: def __init__(self, name, cd, time, distance): self.name = name self.cd = cd self.time = time self.atk_distance = distance @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value @property def cd(self): return self.__cd @cd.setter def cd(self, value): self.__cd = value @property def time(self): return self.__time @time.setter def time(self, value): self.__time = value @property def atk_distance(self): return self.__atk_distance @atk_distance.setter def atk_distance(self, value): self.__atk_distance = value def print_self(self): print(self.name, self.cd, self.time, self.atk_distance) list_skills = [ SkillData("降龙十八掌", 60, 10, 5), SkillData("如来神掌", 50, 5, 15), SkillData("六脉神剑", 80, 20, 8), SkillData("一阳指", 20, 50, 15), SkillData("冷酷追击", 15, 30, 9), ] # -- 查找名称是"降龙十八掌"的技能对象 for item in list_skills: if item.name == "降龙十八掌": item.print_self() # -- 查找名称是持续时间大于10秒的的所有技能对象 result = [] for item in list_skills: if item.time > 10: result.append(item) # -- 查找攻击距离最远的技能对象 result = list_skills[0] for i in range(1, len(list_skills)): # 后面的技能对象 if result.atk_distance < list_skills[i].atk_distance: result = list_skills[i] # result.atk_distance = list_skills[i].atk_distance result.print_self() # -- 按照持续时间,对列表升序排列. for r in range(len(list_skills) - 1): for c in range(r + 1, len(list_skills)): if list_skills[r].time > list_skills[c].time: list_skills[r],list_skills[c] = list_skills[c],list_skills[r] # 请用调试,查看列表的取值. print(list_skills)
练习3:
# 练习: 小明在招商银行取钱. class Person: def __init__(self, name, money=0): self.name = name self.money = money class Bank: def __init__(self, name, money): self.name = name self.total_money = money # 考虑:取钱逻辑,应该由银行决定.所以取钱方法,定义在了银行. def draw_money(self, person, value): if self.total_money >= value: self.total_money -= value person.money += value print(person.name, "取钱成功") else: print("取钱失败") p01 = Person("小明") b01 = Bank("招商银行", 100000) b01.draw_money(p01, 10000000)
练习4
""" 学生管理器系统 """ class StudentModel: """ 学生数据模型类 """ def __init__(self, name="", age=0, score=0, id=0): """ 创建学生对象 :param id: 编号 :param name: 姓名 :param age: 年龄 :param score: 成绩 """ self.id = id self.name = name self.age = age self.score = score @property def id(self): return self.__id @id.setter def id(self, value): self.__id = value @property def name(self): return self.__name @name.setter def name(self, value): self.__name = value @property def age(self): return self.__age @age.setter def age(self, value): self.__age = value @property def score(self): return self.__score @score.setter def score(self, value): self.__score = value class StudentManagerController: """ 学生逻辑控制器 """ def __init__(self): self.__list_stu = [] @property def list_stu(self): return self.__list_stu def add_student(self, stu): """ 添加新学生 :param stu: 需要添加的学生对象 """ stu.id = self.__generate_id() self.__list_stu.append(stu) def __generate_id(self): # 生成编号的需求:新编号,比上次添加的对象编号多1. # if len(self.__list_stu) > 0: # id = self.__list_stu[-1].id + 1 # else: # id = 1 # return id return self.__list_stu[-1].id + 1 if len(self.__list_stu) > 0 else 1 # controller = StudentManagerController() # controller.add_student(StudentModel("zs",18,85)) # controller.add_student(StudentModel("zs",18,85)) # for item in controller.list_stu: # print(item.id,item.name,item.age,item.score) class StudentManagerView: """ 界面视图类 """ def __init__(self): # 创建逻辑控制器对象 self.__manager = StudentManagerController() def __input_students(self): # 1. 在控制台中录入学生信息,存成学生对象StudentModel. stu = StudentModel() stu.name = input("请输入姓名:") stu.age = int(input("请输入年龄:")) stu.score = int(input("请输入成绩:")) # 2. 调用逻辑控制器的add_student方法 self.__manager.add_student(stu) print(self.__manager) def __display_menu(self): """ 显示菜单 :return: """ print("1) 添加学生") print("2) 显示学生") print("3) 删除学生") print("4) 修改学生") print("5) 按照成绩降序排列") def __select_menu(self): """ 选择菜单 :return: """ number = input("请输入选项:") if number == "1": self.__input_students() elif number == "2": pass elif number == "3": pass elif number == "4": pass elif number == "5": pass def main(self): """ 界面入口方法 :return: """ while True: self.__display_menu() self.__select_menu() view = StudentManagerView() view.main()
内存图如下:
练习5
# 1. 使用面向对象思想,写出下列场景: # 玩家(攻击力)攻击敌人,敌人受伤(血量)后掉血,还可能死亡(播放动画). # 敌人(攻击力)攻击力攻击玩家,玩家(血量)受伤后碎屏,还可能死亡(游戏结束). # 程序调试,画出内存图. class Player: """ 玩家类 """ def __init__(self,hp,atk): self.atk = atk self.hp = hp def attack(self,enemy): print("打死你") # 调用敌人受伤方法(敌人负责定义受伤逻辑) enemy.damage(self.atk) def damage(self,value): self.hp -= value print("玩家受伤啦,屏幕碎啦") if self.hp <= 0: self.__death() def __death(self): print("玩家死亡,游戏结束") class Enemy: def __init__(self,hp,atk): self.hp = hp self.atk = atk def damage(self,value): self.hp -= value print("受伤啦") if self.hp <= 0: self.__death() def attack(self,player): print("打死你") player.damage(self.atk) def __death(self): print("死啦,播放动画") p01 = Player(100,50) e01 = Enemy(60,10) # 玩家打敌人 p01.attack(e01) # p01.attack(e01) e01.attack(p01)
内存图如下: