pt05Encapsulation&inherit

Encapsulation &inherit 封装继承

封装

向类外提供必要的功能,隐藏实现的细节, 代码可读性更高

优势:简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。

私有成员:
	作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
	做法:命名使用双下划线开头。
	本质:障眼法,实际也可以访问。
	私有成员的名称被修改为:类名.__成员名,可以通过__dict__属性查看。

私有化:以双下划线开头

"""
    私有化
        作用:类中成员,在类外无法访问
        语法:
            命名: 以双下划线开头
        本质:
            障眼法
                看上去是私有变量名 __data
                实际上是:单下划线+类名+私有变量名   _MyClass__data
"""


class MyClass:
    def __init__(self):
        # 私有的实例变量
        self.__data = 10
    # 私有的方法
    def __func01(self):
        print(self.__data)

    def func02(self):
        # 公开方法,可以访问私有成员
        print(self.__data)
        self.__func01()

m = MyClass()
print(m.__dict__)    # {'_MyClass__data': 10}
print(m._MyClass__data)  #10  私有变量名__data,实际上调用是_MyClass__data,前提是你知道这么多信息


print(m.__data)  # 不能直接访问私有成员,报错
m.__func01()    # 不能直接访问私有成员,报错
m.func02()    # 只能访问公开成员    10   \n 10

shift+F6 批量更改 refactor,do refactor

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2Xo9dNs-1680706395708)(picture\26235120.png)]

练习
"""
    学生信息管理系统MVC
    练习1:将商品控制器的开始编号,
        由实例变量改为类变量
        (即使有多个控制器,也能操作一个开始编号,实现编号唯一)

    练习2:封装商品信息管理系统
         尽量隐藏V与C中不对外提供的成员

    练习3:将商品信息管理系统中C的列表改为只读属性
"""


class StudentModel:
    def __init__(self, name="", age=0, score=0.0, sid=0):
        self.name = name
        self.age = age
        self.score = score
        # 由系统决定的全球唯一标识符(不是用户输入的)
        self.sid = sid


class StudentView:
    """
        学生视图:输入/输出学生信息
    """

    def __init__(self):
        self.__controller = StudentController()

    def __display_menu(self):
        print("按1键录入学生信息")
        print("按2键显示学生信息")
        print("按3键删除学生信息")
        print("按4键修改学生信息")
        print("按5键根据成绩显示学生信息")

    def __select_menu(self):
        item = input("请输入选项:")
        if item == "1":
            self.__input_student()
        elif item == "2":
            # 先写出调用函数代码,再快捷键生成定义函数代码
            # alt + 回车
            self.__display_students()
        elif item == "3":
            self.__delete_student()
        elif item == "4":
            self.__set_student()
        elif item == "5":
            self.__order_by_score()

    def __input_student(self):
        stu = StudentModel()
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        self.__controller.add_student(stu)

    def main(self):
        while True:
            self.__display_menu()
            self.__select_menu()

    def __display_students(self):
        for item in self.__controller.list_student:
            print(f"{item.name}的编号是{item.sid},年龄是{item.age},成绩是{item.score}")

    def __delete_student(self):
        sid = int(input("请输入需要删除的学生编号:"))
        if self.__controller.remove_student(sid):
            print("删除成功")
        else:
            print("删除失败")

    def __set_student(self):
        stu = StudentModel()
        stu.sid = input("请输入学生编号:")
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        if self.__controller.update_student(stu):
            print("修改成功")
        else:
            print("修改失败")

    def __order_by_score(self):
        self.__controller.ascending_order()
        self.__display_students()


class StudentController:
    """
        学生控制器:处理核心功能,存储...
    """

    __start_id = 100  # 大家的:系统不同界面使用的学生编号是一份(连续增加)

    @classmethod
    def __set_student_id(cls, stu):
        cls.__start_id += 1
        stu.sid = cls.__start_id

    def __init__(self):
        self.__list_student = []  # 自己的:系统不同界面使用自己数据(可以显示不同数据)

    @property  # 只读属性:View类只能读取,不能修改
    def list_student(self):
        return self.__list_student

    def add_student(self, new_stu):
        # 设置学生编号
        StudentController.__set_student_id(new_stu)
        # 追加到列表中
        self.__list_student.append(new_stu)

    def remove_student(self, sid):
        """
            在列表中删除学生信息
        :param sid: 学生编号
        :return: 是否成功
        """
        for i in range(len(self.__list_student)):
            if self.__list_student[i].sid == sid:
                del self.__list_student[i]
                return True  # 删除成功
        return False  # 删除失败

    def update_student(self, stu):
        """

        :param stu:
        :return:
        """
        for i in range(len(self.__list_student)):
            if self.__list_student[i].sid == stu.sid:
                # self.list_student[i].name = stu.name
                # self.list_student[i].age = stu.age
                # self.list_student[i].score = stu.score
                self.__list_student[i].__dict__ = stu.__dict__
                return True
        return False

    def ascending_order(self):
        for r in range(len(self.__list_student) - 1):
            for c in range(r + 1, len(self.__list_student)):
                if self.__list_student[r].score > self.__list_student[c].score:
                    self.__list_student[r], self.__list_student[c] = self.__list_student[c], self.__list_student[r]


# 入口
view = StudentView()
view.main()   #view.时,别的都不显示了

练习

"""
    属性-原理
        作用:对实例变量进行有效性验证
    练习: 创建敌人类,并保护数据在有效范围内
        数据:姓名、攻击力、血量
                 0-100   0-500
"""
# 需求:限制age在有效范围之内  20~30
# 步骤:
# 1. 私有化实例变量
# 2. 提供公开的读写方法
class Wife:
    def __init__(self, name="", age=0):
        self.name = name
        # self.__age = age  #私有化,注释掉不调用,走下面的set_age
        self.set_age(age)   #调用下面

    def set_age(self, value):
        if value > 30:
            value = 30
        elif value < 20:
            value = 20
        self.__age = value   #不能直接调,必须走set_age,过条件设置

    def get_age(self):
        return self.__age


shuang_er = Wife("双儿", 260)
# shuang_er.age = 350
shuang_er.set_age(350)
print(shuang_er.name)
# print(shuang_er.age)
print(shuang_er.get_age())     #  debug下看过程

练习: 创建敌人类,并保护数据在有效范围内 原理了解

"""
   练习: 创建敌人类,并保护数据在有效范围内
    数据:姓名、攻击力、血量
              0-100   0-500
"""


class Enemy:
    def __init__(self, name="", atk=0, hp=0):
        self.name = name
        # self.__atk = atk
        self.set_atk(atk)
        self.set_hp(hp)

    def set_atk(self, value):
        if value < 0:
            value = 0
        elif value > 100:
            value = 100
        self.__atk = value

    def get_atk(self):
        return self.__atk

    def set_hp(self, value):
        if value > 500:
            value = 500
        elif value < 0:
            value = 0
        self.__hp = value

    def get_hp(self):
        return self.__hp


mie_ba = Enemy("灭霸", 100, 50000000)
print(mie_ba.name)
# print(mie_ba.atk)
print(mie_ba.get_atk())
# print(mie_ba.hp)
print(mie_ba.get_hp())

过度版本(了解)

"""
    属性 property - 过度
        属性就是包装了读取函数与写入函数的对象
"""


class Wife:
    def __init__(self, name="", age=0):
        self.name = name
        # self.set_age(age)
        self.age = age   #调用下面创建属性对象age

    def set_age(self, value):
        if value > 30:
            value = 30
        elif value < 20:
            value = 20
        self.__age = value

    def get_age(self):
        return self.__age

    # 创建属性对象(读取函数,写入函数)
    age = property(get_age, set_age)   #连接上面两个函数


shuang_er = Wife("双儿", 260)
shuang_er.age = 350   #debug看过程
# shuang_er.set_age(350)
print(shuang_er.name)
print(shuang_er.age)
# print(shuang_er.get_age())

属性 :保护实例变量

标准属性书写
"""
    属性 property - 标准
        属性保护实例变量
            属性中操作的是私有变量
"""


class Wife:
    def __init__(self, name="", age=0):
        self.name = name
        self.age = age

    @property  # age = property(   age    )
    def age(self):
        return self.__age

    @age.setter  # age = age.setter( age   )
    def age(self, value):
        if value > 30:
            value = 30
        elif value < 20:
            value = 20
        self.__age = value


shuang_er = Wife("双儿", 260)
print(shuang_er.__dict__)
shuang_er.age = 350
print(shuang_er.name)
print(shuang_er.age)

练习

"""
   练习: 创建敌人类,并保护数据在有效范围内
    数据:姓名、攻击力、血量
​              0-100   0-500
"""


class Enemy:
    def __init__(self, name="", atk=0, hp=0):
        self.name = name
        self.atk = atk
        self.hp = hp

    @property
    def atk(self):
        return self.__atk

    @atk.setter
    def atk(self, value):
        if value < 0:
            value = 0
        elif value > 100:
            value = 100
        self.__atk = value

    @property
    def hp(self):
        return self.__hp

    @hp.setter
    def hp(self, value):
        if value < 0:
            value = 0
        elif value > 500:
            value = 500
        self.__hp = value


mie_ba = Enemy("灭霸", 100, 50000000)
print(mie_ba.name)
print(mie_ba.atk)
print(mie_ba.hp)
读写、只读、只写属性写法
"""
    属性各种写法

"""


# 1. 读写属性: 对读取和写入过程进行逻辑处理
# 快捷键: 输入props + 回车
class MyClass:
    def __init__(self, data=""):
        self.data = data

    @property
    def data(self):
        return self.__data

    @data.setter
    def data(self, value):
        self.__data = value


m = MyClass("数据")
print(m.data)


# 2. 只读属性: 对私有变量,向类外提供读取操作
# 快捷键: prop + 回车
class MyClass:
    def __init__(self):
        self.__data = "数据"   #对私有变量,向类外提供读取操作

    @property
    def data(self):
        return self.__data


m = MyClass()

# m.data = "新数据"  # AttributeError: can't set attribute
print(m.data)


# 3. 只写属性:使用较少,只能修改,不能读取.   
# 快捷键:无
class MyClass:
    def __init__(self, data=""):
        self.data = data

    # @property # data = property(  data )
    # def data(self):
    #     return self.__data

    # 写法1:
    # data = property()
    #
    # @data.setter
    # def data(self, value):
    #     self.__data = value

    # 写法2:   
    def data(self, value):
        self.__data = value

    data = property(fset=data)


m = MyClass("数据")
# print(m.data)  # AttributeError: unreadable attribute
m.data = "新数据"
print(m.__dict__)

练习

"""
    练习2:创建技能类,并保护数据在有效范围内
    数据:技能名称、冷却时间、攻击力度、消耗法力
​                0 -- 120  0 -- 200  100 -- 100
"""


class Skill:
    def __init__(self, name="", cooling_time=0, atk=0):
        self.name = name
        self.cooling_time = cooling_time
        self.atk = atk
        self.__cost_sp = 100

    @property
    def cooling_time(self):
        return self.__cooling_time

    @cooling_time.setter
    def cooling_time(self, value):
        if value < 0: value = 0
        if value > 120: value = 120
        self.__cooling_time = value

    @property
    def atk(self):
        return self.__atk

    @atk.setter
    def atk(self, value):
        if value < 0: value = 0
        if value > 200: value = 200
        self.__atk = value

    @property
    def cost_sp(self):
        return self.__cost_sp


slsbz = Skill("降龙十八掌", 100, 100)
print(slsbz.__dict__)

练习

"""
   创建桌子类,保护数据在有效范围内
        数据:品牌,       材质,         尺寸(120,60,80)
                [实木,板材,金属]其中之一    长度为3

"""


class Desk:
    def __init__(self, brand="", material="", size=()):
        self.brand = brand
        self.material = material
        self.size = size

    @property  # 函数 = property(函数)
    def material(self):
        return self.__material

    @material.setter  # 函数 = material.setter(函数)
    def material(self, value):
        if value in ("实木", "板材", "金属"):
            self.__material = value
        else:
            self.__material = "实木"

    @property
    def size(self):
        return self.__size

    @size.setter
    def size(self, value):
        if len(value) == 3:
            self.__size = value
        else:
            self.__size = (120, 60, 80)


lege = Desk("乐歌", "金属", (112, 29.5, 16))
print(lege.brand)
print(lege.material)
print(lege.size)
print(lege.__dict__)

继承

继承方法

继承 - 行为
    皇位:江山不用太子打,但是可以直接坐
    编程:代码不用子类写,但是可以直接用
    
class 父类:
    def 父类方法(self):
        方法体
        
class 子类(父类)def 子类方法(self):
        方法体
        
儿子 = 子类()  
儿子.子类方法()   
儿子.父类方法()     #子类直接拥有父类的方法.

内置函数

(1) isinstance(对象, 类型)  返回指定对象是否是某个类的对象。
(2) issubclass(类型,类型)  返回指定类型是否属于某个类型。

演示

# 多个类型在概念上是统一的,在成员上有重复.
#    def say(self) 重复

class Student:
    def say(self):
        print("说话")

    def play(self):
        print("玩耍")

class Teacher:
    def say(self):
        print("说话")

    def teach(self):
        print("教学")
class Person:
    def say(self):
        print("说话")


class Student(Person):
    def play(self):
        print("玩耍")
        self.say()


class Teacher(Person):
    def teach(self):
        print("教学")
        
# 子类既可以访问自己成员,也可以访问父类成员(不劳而获)
qtx = Teacher()
qtx.say()
qtx.teach()

# 父类只能访问自己的成员
zs = Person()
zs.say()  

关系判定

# 1.对象是一种类型
# 老师对象是一种老师类型
print(isinstance(qtx, Teacher))  # True
# 老师对象是一种人类型
print(isinstance(qtx, Person))  # True
# 人对象是一种老师类型
print(isinstance(zs, Teacher))  # False
# 老师对象是一种学生类型
print(isinstance(qtx, Student))  # False

# 2.类型是一种类型
# 老师类型是一种老师类型
print(issubclass(Teacher, Teacher))  # True
# 老师类型是一种人类型
print(issubclass(Teacher, Person))  # True
# 人类型是一种老师类型
print(issubclass(Person, Teacher))  # False
# 老师类型是一种学生类型
print(issubclass(Teacher, Student))  # False

# 3. 对象是类型
# 老师对象是老师类型
print(type(qtx) == Teacher)  # True
# 老师对象是人类型
print(type(qtx) == Person)  # False
# 人对象是老师类型
print(type(zs) == Teacher)  # False
# 老师对象是学生类型
print(type(qtx) == Student)  # False

练习

""
    创建子类:狗(),鸟类()
    创建父类:动物()
    体会子类复用父类方法
    体会 isinstanceissubclasstype 的作用.
"""


class Animal:
    def eat(self):
        print("吃")


class Dog(Animal):
    def run(self):
        self.eat()
        print("跑")


class Bird(Animal):
    def fly(self):
        print("飞")


a01 = Animal()
d01 = Dog()
b01 = Bird()

d01.run()   #  吃 \n 跑
d01.eat()   #  吃

# 类型 与 类型 的关系
print(issubclass(Animal, Dog))  # False

# 对象 与 类型 的关系
print(isinstance(b01, Animal))  # True

# 狗对象 与 动物类型 相同
print(type(d01) == Animal)  # False

继承数据

class 子类(父类):
    def __init__(self,父类参数,子类参数):
        super().__init__(参数) # 调用父类构造函数
        self.实例变量 = 参数
"""
    继承数据
"""
# 1. 子类如果没有构造函数,直接使用父类构造函数.
class Person:
    def __init__(self, name="", age=0):
        self.name = name
        self.age = age

class Student(Person):
    pass
 
zs = Student("张三", 26)
print(zs.__dict__)


# 2. 子类如果有构造函数,会覆盖父类构造函数,好像他不存在.

class Student(Person):
     def __init__(self, score=0):
        self.score = score   
zs = Student(100)
print(zs.__dict__)  #{'score': 100}

#    此时必须通过super()函数调用父类构造函数
class Student(Person):        # 注意:子类构造函数参数:父类+子类
    def __init__(self, name="", age=0, score=0):
        super().__init__(name, age)#debug,到此会调上面的person类创建name、age,再创建自己的score
        self.score = score


zs = Student(100)
print(zs.__dict__)  #  {'name': 100, 'age': 0, 'score': 0}

zs = Student("张三", 26, 100)
print(zs.__dict__)   #{'name': '张三', 'age': 26, 'score': 100}

练习

"""
    父类:车(品牌,速度)
    创建子类:电动车(电池容量,充电功率)
"""

class Car:
    def __init__(self, brand, speed):
        self.brand = brand
        self.speed = speed

class ElectricCars(Car):
    # 1. 子类构造函数参数:父类参数+子类参数
    def __init__(self, brand, speed, battery_capacity, charging_power):
        # 2. 通过super调用父类构造函数
        super().__init__(brand, speed)
        self.battery_capacity = battery_capacity
        self.charging_power = charging_power

bc = Car("奔驰", 220)
print(bc.__dict__)  #{'brand': '奔驰', 'speed': 220}

am = ElectricCars("艾玛", 180, 10000, 220)
print(am.__dict__) #{'brand': '艾玛', 'speed': 180, 'battery_capacity': 10000, 'charging_power': 220}

定义了解

(1) 概念: 重用现有类的功能,并在此基础上进行扩展。
(2) 说明:子类直接具有父类的成员(共性),还可以扩展新功能。
(3) 相关知识
		父类(基类、超类)、子类(派生类)。
		父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。
		单继承:父类只有一个(例如 Java,C#)。
		多继承:父类有多个(例如C++,Python)。
		Object类:任何类都直接或间接继承自 object 类。

多态

(1) 字面意思:对于一种行为有不同表现形态。
(2) 概念:对于父类的一个方法,在不同的子类上有不同体现。
(3) 说明:编码时调用父类方法,运行时传递子类对象执行子类方法。

重写

(1) 定义:在子类定义与父类相同的方法。
(2) 作用:改变父类行为,体现子类个性。

重写内置函数str

(1) 定义:Python中,以双下划线开头、双下划线结尾的是系统定义的成员。我们可以在自定义类中进
行重写,从而改变其行为。
(2) __str__ 函数:将对象转换为字符串(对人友好的)
"""
    重写内置函数
        重写:子类具有与父类名称相同的函数
        目的:改变其行为
"""
class Person(object):
    def __init__(self, name="", age=0):
        self.name = name
        self.age = age
#zs = Person("张三",36)
#print(zs)    #<__main__.Person object at 0x01C4E350>,直接打印的结果

    # 自定义对象转换-->字符串
    def __str__(self):
        return "姓名是zs,年龄是26"

    # 自定义对象-->整数
    # def __int__(self):
    #     return self.age


zs = Person("张三",36)
# <__main__.Person object at 0x7f03d5e76e80>

# 打印自定义对象时,会自动调用__str__
print(zs)  #姓名是zs,年龄是26

​ 练习:

"""
        直接打印商品对象: xx的编号是xx,单价是xx
        直接打印敌人对象: xx的攻击力是xx,血量是xx
"""


class Commodity:
    def __init__(self, cid=0, name="", price=0):
        self.cid = cid
        self.name = name
        self.price = price
#c01 = Commodity(1001, "屠龙刀", 10000)
#print(c01) #<__main__.Commodity object at 0x00EEE350>
    def __str__(self):
        return f"{self.name}的编号是{self.cid},单价是{self.price}"

class Enemy:
    def __init__(self, name="", atk=0, hp=0):
        self.name = name
        self.atk = atk
        self.hp = hp

    def __str__(self):
        return "%s的攻击力是%d,血量是%d" % (self.name, self.atk, self.hp)

c01 = Commodity(1001, "屠龙刀", 10000)
print(c01) # 自动调用__str__   屠龙刀的编号是1001,单价是10000

e01 = Enemy("灭霸")
print(e01) # 自动调用__str__    灭霸的攻击力是0,血量是0

运算符重载(重写)

"""
    运算符重载(重写)
        算数运算符
"""
class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # +
    def __add__(self, other):
        # print(type(qtx) == Teacher)
        if type(other) == Vector2:   #判断是否是向量类型eg:(3,2)
            x = self.x + other.x
            y = self.y + other.y
        else:
            x = self.x + other
            y = self.y + other
        return Vector2(x, y)


pos01 = Vector2(3, 2)
pos02 = Vector2(5, 3)
pos03 = pos01 + pos02  # pos01.__add__(pos02)
print(pos03.__dict__)  #{'x': 8, 'y': 5}

pos05 = pos01 + 6  # pos01.__add__(6)  #6不是向量,pos01值都加6
print(pos05.__dict__)  #{'x': 9, 'y': 8}

算数运算符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m9qwWSiy-1680706395709)(picture\328220422.png)]

复合运算符重载

"""
    练习:创建颜色类,数据包含r、g、b、a,实现颜色对象相加。
"""
class Color:
    def __init__(self, r, g, b, a):
        self.r = r
        self.g = g
        self.b = b
        self.a = a

    def __sub__(self, other):
        if type(other) == Color:
            r = c01.r - other.r
            g = c01.g - other.g
            b = c01.b - other.b
            a = c01.a - other.a
        else:
            r = c01.r - other
            g = c01.g - other
            b = c01.b - other
            a = c01.a - other
        return Color(r, g, b, a)


c01 = Color(50, 0, 0, 200)
c02 = Color(0, 100, 0, 100)
c03 = c01 - c02  # c01.__sub__(c02)
print(c03.__dict__)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3SG9Y4qK-1680706395710)(picture\28222439.png)]

"""
    运算符重载(重写)
        增强运算符
"""
class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # + 返回新数据
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector2(x, y)

    # += 返回旧数据
    def __iadd__(self, other):
        self.x += other.x
        self.y += other.y
        return self


pos01 = Vector2(3, 2)
pos02 = Vector2(5, 3)
print(id(pos01))  # 31122256
pos01 += pos02  # pos01.__iadd__(pos02)
print(id(pos01))  # 31122256
print(pos01.__dict__)  #{'x': 8, 'y': 5}

# 不可变数据的+=,在原有基础上改变
data01 = [10]
print(id(data01))    #15615480
data01 += [20]
print(id(data01))  #15615480
print(data01)   #[10, 20]

# 不可变数据的+=,创建了新数据
data01 = (10,)
print(id(data01))  # 26052048
data01 += (20,)
print(id(data01))  # 27950496
print(data01)   #(10, 20)
"""
    练习:创建颜色类,数据包含r、g、b、a,实现颜色对象累加。
"""


class Color:
    def __init__(self, r, g, b, a):
        self.r = r
        self.g = g
        self.b = b
        self.a = a

    def __imul__(self, other):
        self.r *= other.r
        self.g *= other.g
        self.b *= other.b
        self.a *= other.a
        return self


c01 = Color(50, 0, 0, 200)
c02 = Color(0, 100, 0, 100)
c01 *= c02
print(c01.__dict__)

比较运算重写使用较多

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-peNMZGu0-1680706395711)(picture\328222845.png)]

"""
    运算符重载(重写)
        比较运算符
"""
"""
class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
pos01 = Vector2(3, 2)
pos02 = Vector2(3, 2)
print(pos01 == pos02)  # False   需要重写__eq__

list_data = [
    Vector2(1, 1),
    Vector2(3, 3),
    Vector2(2, 2),
    Vector2(5, 5),
    Vector2(4, 4),
]
print(Vector2(1, 1) in list_data)  #False
list_data.remove(Vector2(3, 3))  #list.remove(x): x not in list
print(list_data)  #[<__main__.Vector2 object at 0x013CED10>, <__main__.Vector2 object at 0x014B2530>, <__main__.Vector2 object at 0x014B23D0>, <__main__.Vector2 object at 0x014B2510>, <__main__.Vector2 object at 0x014B23F0>]
"""
###需要重写__eq__##########
class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # 相同的依据
    def __eq__(self, other):
        # return self.x == other.x and self.y == other.y
        return self.__dict__ == other.__dict__

    # 大小的依据
    def __gt__(self, other):
        return self.x ** 2 + self.y ** 2 > other.x ** 2 + other.y ** 2


# 1. 需要重写__eq__
pos01 = Vector2(3, 2)
pos02 = Vector2(3, 2)
print(pos01 == pos02)  # True
list_data = [
    Vector2(1, 1),
    Vector2(3, 3),
    Vector2(2, 2),
    Vector2(5, 5),
    Vector2(4, 4),
]
print(Vector2(1, 1) in list_data)  #True
list_data.remove(Vector2(3, 3))
print(list_data)  #[<__main__.Vector2 object at 0x01F2ED10>, <__main__.Vector2 object at 0x02012510>, <__main__.Vector2 object at 0x020123F0>, <__main__.Vector2 object at 0x02012470>]


value = max(list_data)   #需要重新__gt__,向量大小看平方和
print(value.__dict__)  #{'x': 5, 'y': 5}


list_data.sort()  # 升序排列
list_data.sort(reverse=True)  # 降序排列
print(list_data)  #[<__main__.Vector2 object at 0x020123F0>, <__main__.Vector2 object at 0x02012470>, <__main__.Vector2 object at 0x02012510>, <__main__.Vector2 object at 0x01F2ED10>]
"""
    练习:
    创建颜色列表,实现in、count、index、max、sort运算
"""


class Color:
    def __init__(self, r, g, b, a):
        self.r = r
        self.g = g
        self.b = b
        self.a = a

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __gt__(self, other):
        return self.a > other.a


list_data = [
    Color(1, 1, 1, 1),
    Color(2, 2, 2, 2),
    Color(4, 4, 4, 4),
    Color(3, 3, 3, 3),
]
print(Color(3, 3, 3, 3) in list_data)  # 内部自动调用eq

max_value = max(list_data)  # 内部自动调用gt
print(max_value.__dict__)
"""
    学生信息管理系统MVC练习:
        --在View直接打印商品 __str__
        --在Controller通过remove __eq__
        --在Controller通过sort排序__gt__
"""


class StudentModel:
    def __init__(self, name="", age=0, score=0.0, sid=0):
        self.name = name
        self.age = age
        self.score = score
        self.sid = sid

    # 两个学生对象是否相同的依据:编号
    def __eq__(self, other):
        return self.sid == other.sid

    # 两个学生对象大小的依据:成绩
    def __gt__(self, other):
        return self.score > other.score

    # 显示学生的风格
    def __str__(self):
        return f"{self.name}的编号是{self.sid},年龄是{self.age},成绩是{self.score}"


class StudentView:
    """
        学生视图:输入/输出学生信息
    """

    def __init__(self):
        self.__controller = StudentController()

    def __display_menu(self):
        print("按1键录入学生信息")
        print("按2键显示学生信息")
        print("按3键删除学生信息")
        print("按4键修改学生信息")
        print("按5键根据成绩显示学生信息")

    def __select_menu(self):
        item = input("请输入选项:")
        if item == "1":
            self.__input_student()
        elif item == "2":
            # 先写出调用函数代码,再快捷键生成定义函数代码
            # alt + 回车
            self.__display_students()
        elif item == "3":
            self.__delete_student()
        elif item == "4":
            self.__set_student()
        elif item == "5":
            self.__order_by_score()

    def __input_student(self):
        stu = StudentModel()
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        self.__controller.add_student(stu)

    def main(self):
        while True:
            self.__display_menu()
            self.__select_menu()

    def __display_students(self):
        for item in self.__controller.list_student:
            # print(f"{item.name}的编号是{item.sid},年龄是{item.age},成绩是{item.score}")
            print(item)


    def __delete_student(self):
        sid = int(input("请输入需要删除的学生编号:"))
        if self.__controller.remove_student(sid):
            print("删除成功")
        else:
            print("删除失败")

    def __set_student(self):
        stu = StudentModel()
        stu.sid = input("请输入学生编号:")
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        if self.__controller.update_student(stu):
            print("修改成功")
        else:
            print("修改失败")

    def __order_by_score(self):
        self.__controller.ascending_order()
        self.__display_students()


class StudentController:
    """
        学生控制器:处理核心功能,存储...
    """

    __start_id = 100  # 大家的:系统不同界面使用的学生编号是一份(连续增加)

    @classmethod
    def __set_student_id(cls, stu):
        cls.__start_id += 1
        stu.sid = cls.__start_id

    def __init__(self):
        self.__list_student = []  # 自己的:系统不同界面使用自己数据(可以显示不同数据)

    @property  # 只读属性:View类只能读取,不能修改
    def list_student(self):
        return self.__list_student

    def add_student(self, new_stu):
        # 设置学生编号
        StudentController.__set_student_id(new_stu)
        # 追加到列表中
        self.__list_student.append(new_stu)

    def remove_student(self, sid):
        """
            在列表中删除学生信息
        :param sid: 学生编号
        :return: 是否成功
        """
        stu = StudentModel(sid=sid)
        if stu in self.__list_student:
            # 重写Model类的eq方法
            self.__list_student.remove(stu)
            return True
        return False

    def update_student(self, stu):
        """

        :param stu:
        :return:
        """
        for i in range(len(self.__list_student)):
            if self.__list_student[i].sid == stu.sid:
                # self.list_student[i].name = stu.name
                # self.list_student[i].age = stu.age
                # self.list_student[i].score = stu.score
                self.__list_student[i].__dict__ = stu.__dict__
                return True
        return False

    def ascending_order(self):
        self.__list_student.sort()

# 入口
view = StudentView()
view.main()

"""
    练习:重构商品信息管理系统中
    --在View直接打印商品 __str__
    --在Controller通过remove移除商品 __eq__
    --在Controller通过sort排序__gt__
"""


class CommodityModel:
    """
        商品模型:包装具体商品信息
    """

    def __init__(self, name="", price=0, cid=0):
        self.name = name
        self.price = price
        self.cid = cid

    def __str__(self):
        return "%s的编号是%s,单价是%s" % (self.name, self.cid, self.price)

    def __eq__(self, other):
        return  self.cid == other.cid

    def __gt__(self, other):
        return self.price > other.price


class CommodityView:
    """
        商品视图:处理商品界面逻辑,例如:输入输出商品信息
    """

    def __init__(self):
        self.__controller = CommodityController()

    def __display_menu(self):
        print("按1键录入商品信息")
        print("按2键显示商品信息")
        print("按3键删除商品信息")
        print("按4键修改商品信息")
        print("按5键根据单价对商品信息排序")

    def __select_menu(self):
        item = input("请输入选项:")
        if item == "1":
            self.__input_commodity()
        elif item == "2":
            self.__display_commoditys()
        elif item == "3":
            self.__delete_commodity()
        elif item == "4":
            self.__set_commodity()
        elif item == "5":
            self.__order_by_price()

    def __input_commodity(self):
        cmd = CommodityModel()
        cmd.name = input("请输入商品名称:")
        cmd.price = int(input("请输入商品单价:"))
        self.__controller.add_commodity(cmd)

    def main(self):
        while True:
            self.__display_menu()
            self.__select_menu()

    def __display_commoditys(self):
        for item in self.__controller.list_commodity:
            # print("%s的编号是%s,单价是%s" % (item.name, item.cid, item.price))
            print(item) # 内部自动调用商品__str__

    def __delete_commodity(self):
        cid = int(input("请输入需要删除的编号:"))
        if self.__controller.remove_commodity(cid):
            print("删除成功")
        else:
            print("删除失败")

    def __set_commodity(self):
        cmd = CommodityModel()
        cmd.cid = int(input("请输入商品编号:"))
        cmd.name = input("请输入商品名称:")
        cmd.price = int(input("请输入商品单价:"))
        if self.__controller.update_commodity(cmd):
            print("修改成功")
        else:
            print("修改失败")

    def __order_by_price(self):
        self.__controller.ascending_order()
        self.__display_commoditys()


class CommodityController:
    """
        商品控制器:处理商品业务逻辑,例如:存储信息
    """

    __start_id = 100  # 共享,只有一份

    @classmethod
    def __set_commodity_id(cls, cmd):
        cmd.cid = cls.__start_id
        cls.__start_id += 1

    def __init__(self):
        self.list_commodity = []  # 独享,每个对象都有

    def add_commodity(self, new_cmd):
        CommodityController.__set_commodity_id(new_cmd)
        self.list_commodity.append(new_cmd)

    def remove_commodity(self, cid):
        """

        :param cid:
        :return:
        """
        cmd = CommodityModel(cid = cid)
        if cmd in self.list_commodity:
            self.list_commodity.remove(cmd)# 内部自动调用商品的__eq__
            return True
        return False

    def update_commodity(self, cmd):
        """"""
        for i in range(len(self.list_commodity)):
            if self.list_commodity[i].cid == cmd.cid:
                self.list_commodity[i].__dict__ = cmd.__dict__
                return True
        return False

    def ascending_order(self):
        self.list_commodity.sort() # 内部自动调用商品的__gt__


view = CommodityView()
view.main()

练习

"""
    增加新功能:
        飞机
"""
# 缺点:违反了面向对象设计原则--开闭原则
# 允许增加新功能,但是不能修改客户端代码.
"""
class Person:
    def __init__(self, name=""):
        self.name = name

    def go_to(self, position, vehicle):
        print("去" + position)
        if type(vehicle) == Car:
            vehicle.run()
        elif type(vehicle) == Airplane:
            vehicle.fly()

class Car:
    def run(self):
        print("汽车在行驶")


class Airplane:
    def fly(self):
        print("飞机在飞行")


# 在使用时创建
zl = Person("老张")
car = Car()
air = Airplane()
zl.go_to("东北", car)
zl.go_to("东北", air)
"""

# ------------------架构师--------------------
# 客户端代码
class Person:
    def __init__(self, name=""):
        self.name = name

    def go_to(self, position, vehicle):
        print("去" + position)
        # 编码时,调用父类交通工具
        # 运行时,执行子类汽车/飞机
        vehicle.transport()

# 父类(规范)
class Vehicle:
    def transport(self):     #跟上面的transport名字保持一致
        pass

# ------------------程序员--------------------
# 子类(功能实现)
class Car(Vehicle):  #继承
    def transport(self):  #重写
        print("汽车在行驶")


class Airplane(Vehicle):
    # 重写快捷键   ctrl + o
    def transport(self):
        print("飞机在飞行")

# 在使用时创建
zl = Person("老张")
car = Car()
air = Airplane()
zl.go_to("东北", car)
zl.go_to("东北", air)

i].dict = cmd.dict
return True
return False

def ascending_order(self):
    self.list_commodity.sort() # 内部自动调用商品的__gt__

view = CommodityView()
view.main()


练习

```python
"""
    增加新功能:
        飞机
"""
# 缺点:违反了面向对象设计原则--开闭原则
# 允许增加新功能,但是不能修改客户端代码.
"""
class Person:
    def __init__(self, name=""):
        self.name = name

    def go_to(self, position, vehicle):
        print("去" + position)
        if type(vehicle) == Car:
            vehicle.run()
        elif type(vehicle) == Airplane:
            vehicle.fly()

class Car:
    def run(self):
        print("汽车在行驶")


class Airplane:
    def fly(self):
        print("飞机在飞行")


# 在使用时创建
zl = Person("老张")
car = Car()
air = Airplane()
zl.go_to("东北", car)
zl.go_to("东北", air)
"""

# ------------------架构师--------------------
# 客户端代码
class Person:
    def __init__(self, name=""):
        self.name = name

    def go_to(self, position, vehicle):
        print("去" + position)
        # 编码时,调用父类交通工具
        # 运行时,执行子类汽车/飞机
        vehicle.transport()

# 父类(规范)
class Vehicle:
    def transport(self):     #跟上面的transport名字保持一致
        pass

# ------------------程序员--------------------
# 子类(功能实现)
class Car(Vehicle):  #继承
    def transport(self):  #重写
        print("汽车在行驶")


class Airplane(Vehicle):
    # 重写快捷键   ctrl + o
    def transport(self):
        print("飞机在飞行")

# 在使用时创建
zl = Person("老张")
car = Car()
air = Airplane()
zl.go_to("东北", car)
zl.go_to("东北", air)

你可能感兴趣的:(python,python,开发语言)