Encapsulation &inherit 封装继承
3.1.1 数据角度
(1) 定义:将一些基本数据类型复合成一个自定义类型。
(2) 优势: 将数据与对数据的操作相关联。 代码可读性更高(类是对象的模板)。
3.1.2 行为角度
(1) 定义:向类外提供必要的功能,隐藏实现的细节。
(2) 优势:简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
(3) 私有成员:
– 作用:无需向类外提供的成员,可以通过私有化进行屏蔽。
– 做法:命名使用双下划线开头。
– 本质:障眼法,实际也可以访问。
私有成员的名称被修改为:类名*__*成员名,可以通过__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-CzSmVIal-1680018998941)(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
练习
""
创建子类:狗(跑),鸟类(飞)
创建父类:动物(吃)
体会子类复用父类方法
体会 isinstance 、issubclass 与 type 的作用.
"""
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) 作用:改变父类行为,体现子类个性。
重写内置函数
(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-KKcQmAai-1680018998943)(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-gJCWcQnn-1680018998943)(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-VKTlBOdM-1680018998944)(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)