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)

    内存图如下:

    

    

posted @ 2019-04-15 19:06  一如年少模样  阅读(535)  评论(0编辑  收藏  举报