一、封装
数据角度:将一些基本数据类型复合成一个自定义类型。
优势:将数据与对数据的操作相关联。
"""疫情信息管理系统V2封装 将不需要让类外访问的成员变为私有。 封装的时候站在使用者的角度进行考虑,即站在主程序的角度考虑View成员,站在View的角度考虑Model成员 """class EpidemicModel:"""数据模型"""def __init__(self, region="", new=0, now=0, total=0, eid=0):self.region = regionself.new = newself.now = nowself.total = totalself.eid = eid # 操作全球唯一标识符的变量class EpidemicView:"""疫情视图"""def __init__(self):self.__controller = EpidemicController()def __display_menu(self):"""显示菜单"""print("按1键录入疫情信息")print("按2键显示疫情信息")print("按3键删除疫情信息")print("按4键修改疫情信息")def __select_menu(self):"""选择菜单"""number = input("请输入选项:")if number == "1":# 重点1:类中通过self调用self.__input_epidemic()elif number == "2":self.__display_epidemics()elif number == "3":self.__delete_epidemic()elif number == "4":self.__modify_epidemic() def __input_epidemic(self):"""录入疫情信息"""# 重点3:每次录入新数据创建新Model对象# model = EpidemicModel(# input("请输入疫情地区:"),# int(input("请输入现有人数:")),# int(input("请输入新增人数:")),# int(input("请输入累计人数:")),# )# model = EpidemicModel(# region=input("请输入疫情地区:"),# now=int(input("请输入现有人数:")),# new=int(input("请输入新增人数:")),# total=int(input("请输入累计人数:")),# )model = EpidemicModel()model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))self.__controller.add_epidemic(model)def __display_epidemics(self):"""显示所有疫情信息"""for item in self.__controller.list_epidemic:print("%s地区的编号是%s,新增%s人,现有%s人,累计%s人" % (item.region, item.eid, item.new, item.now, item.total))def __delete_epidemic(self):"""删除疫情,录入编号,传递给controller,显示结果"""eid = int(input("请输入需要删除的疫情编号:")) # 将输入的编号转为int类型if self.__controller.remove_epidemic(eid):print("删除成功哦~")else:print("哦~不行")def __modify_epidemic(self):"""修改疫情信息,录入、传递、显示:return:"""model = EpidemicModel()model.eid = int(input("请输入需要需改的疫情编号:"))model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))if self.__controller.update_epidemic(model):print("修改成功")else:print("需改失败")def main(self):"""入口哦"""while True:self.__display_menu()self.__select_menu()class EpidemicController:"""疫情控制器"""def __init__(self):self.list_epidemic = [] # type:list[EpidemicModel]self.__start_id = 1001def add_epidemic(self, info):"""添加疫情信息:param info:EpidemicModel类型,新信息"""# 设置自增长编号info.eid = self.__start_idself.__start_id += 1 # 为下一个数据可以使用不同数据# 添加到列表中self.list_epidemic.append(info)def remove_epidemic(self, eid: int):"""在列表中移除疫情信息:param eid: int类型,疫情编号:return: bool类型,True表达移除成功,False表达移除失败"""for i in range(len(self.list_epidemic)):if self.list_epidemic[i].eid == eid:del self.list_epidemic[i]return True # 循环中途退出,返回成功return False # 列表没有找到,则删除失败# remove内部还有层循环,所以带来二次查找# for item in self.list_epidemic:# 列表名.remove(item)def update_epidemic(self, new):"""更新疫情信息:param new: Model类型:return: bool类型"""# for i in range(len(self.list_epidemic)):# self.list_epidemic[i].region = new.regionfor item in self.list_epidemic:if item.eid == new.eid:# item.region = new.region# item.new = new.new# item.now = new.nowitem.__dict__ = new.__dict__return Truereturn Falseview = EpidemicView() print(view.__dict__) view.main()
二、继承
1、继承方法
适用性:多个类有代码上的共性,且概念上统一
说明:子类直接拥有父类的方法
语法:
class 父类:def 父类方法(self):方法体 class 子类(父类):def 子类方法(self):方法体 儿子 = 子类() 儿子.子类方法() 儿子.父类方法()
演示:
class Person:def say(self):print("讲话")class Student(Person):def play(self):self.say()print("玩耍")class Teacher(Person):def teach(self):print("讲课")t = Teacher()
t.say()
p = Person()
2、内置函数
isinstance(对象, 类型):该方法用来检查给定的对象是否是给定类型的实例或者是给定类型的任意
子类的实例,通常使用该方法进行对象类型校验。
issubclass(class: type, classinfo: Union[type, ...]),用来判断指定的两个类型之间的从属关系
如果【class】是【classinfo】的子类返回真(True),否则返回假(False)
type(o: object):传入一个【object】对象,返回一个类型,通常与object.__class__方法
的返回值相同
案例:
class Person:def say(self):print("讲话")class Student(Person):def play(self):self.say()print("玩耍")class Teacher(Person):def teach(self):print("讲课")t = Teacher()
t.say()
p = Person()
## 关系判定# isinstance(对象, 类型),返回指定对象是否是某个类的对象。# isinstance方法用来检查给定的对象是否是# 给定类型的实例或者是给定类型的任意子类的实例,# 通常使用该方法进行对象类型校验
# 老师对象 是 人类型 True 【人类型包含老师对象】
print(isinstance(t, Person))
# 人对象 是 人类型 True
print(isinstance(p, Person))
# 人对象 是 教师类型 False
print(isinstance(p, Teacher))# issubclass(类型,类型),返回指定类型是否属于某个类型
# issubclass(class: type, classinfo: Union[type, ...])
# 用来判断指定的两个类型之间的从属关系
# 如果【class】是【classinfo】的子类返回真(True),否则返回假(False)
# 老师类型 是 人类型 True
print(issubclass(Teacher, Person))
# 人类型 是 人类型 True
print(issubclass(Person, Person))
# 人类型 是 教师类型 False
print(issubclass(Person, Teacher))# type(o: object)
# 传入一个【object】类型,返回一个【type】对象,通常与object.__class__方法的返回值相同
# 老师对象的类型 是 人类型 False
print(type(t) == Person)
# 人对象的类型 是 人类型 True
print(type(p) == Person)
# 人对象的类型 是 教师类型 False
print(type(p) == Teacher)
3、继承数据
class 子类(父类):def __init__(self,父类参数,子类参数):super().__init__(参数) # 调用父类构造函数self.实例变量 = 参数
说明:子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类实例变量被正常创建。
"""继承数据
"""class Person:def __init__(self, name = "" , age = 0): # 4self.name = nameself.age = age# 子类没有构造函数,直接使用父类构造函数
class Teacher(Person):pass# 子类有构造函数,将覆盖父类构造函数
class Student(Person):# 子类构造函数参数:父类+子类def __init__(self, name="", age=0, score=0): # 2super().__init__(name, age) # 3self.score = scoreqtx = Teacher("齐大胜", 22) # Ctrl+P看提示,继承父类的init函数rc = Student("任聪", 34, 90) # 1
print(rc.name)
相关知识
-- 父类(基类、超类)、子类(派生类)。
-- 父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。
-- 单继承:父类只有一个(例如 Java,C#)。
-- 多继承:父类有多个(例如C++,Python)。
-- Object类:任何类都直接或间接继承自 object 类。
三、多态
字面意思:对于一种行为有不同表现形态。
概念:对于父类的一个方法,在不同的子类上有不同体现。
1、重写的定义
2、重写内置函数
(1)__str__函数
class Person(object):def __init__(self, name="", age=0): # 4self.name = nameself.age = age# 当对象被打印时,自动执行def __str__(self):return f"{self.name}的年龄是{self.age}"wjs = Person("魏剑霜", 26)
# print函数内部,调用的是object类的__str__函数
print(wjs)
(2)__add__函数
被累加的数据:
如果为可变数据:
+=运算符会返回旧数据 调用__iadd__函数
+运算符返回新数据 调用__add__函数
如果为不可变数据 :
+=,+ 都会返回新数据 调用__add__函数
案例1:
'''
被累加的数据:
如果为可变数据: +=运算符会返回旧数据 调用__iadd__函数+运算符返回新数据 调用__add__函数
如果为不可变数据 +=,+ 都会返回新数据 调用__add__函数
'''
# 可变数据
list01 = [10]
print(id(list01)) # 2397935506880
list01 += [20]
print(id(list01)) # 2397935506880# 不可变数据
tuple01 = (10)
print(id(tuple01)) # 140723445966912
tuple01 += (20)
print(id(tuple01)) # 140723445967552
print("-------")
# 面试题
a = 1
print(id(a)) # 140724735125280
a += 2 # a.__add__(2)
print(id(a)) # 140724735125408
a = a + 2 # a.__add__(2)
print(id(a)) # 140724735125344
b = [1]
print(id(b)) # 2632814702784
b += [2] # b.__iadd__([2]) 2632812524224
print(id(b))
b = b + [2] # b.__add__([2]) 2632812524224
print(id(b))
案例2:
"""重写当打印自定义对象时,自动执行__str__函数自定义对象相加时,自动执行__add__函数--通过传入参数的类型决定行为自定义对象累加时,自动执行__iadd__函数--可变数据返回旧数据--不可变数据返回新数据,即自动执行__add__
"""class Vector02:def __init__(self, x ,y):self.x = xself.y = y# 返回新对象def __add__(self, other):# 函数可以根据传入的参数类型,决定行为if type(other) == Vector02:x = self.x + other.xy = self.y + other.yelse:x = self.x + othery = self.y + otherreturn Vector02(x, y)# 累加:返回旧对象def __iadd__(self, other):if type(other) == Vector02:self.x += other.xself.y += other.yelse:self.x += otherself.y += otherreturn Vector02(self.x, self.y)def __sub__(self, other):# 函数可以根据传入的参数类型,决定行为if type(other) == Vector02:x = self.x - other.xy = self.y - other.yelse:x = self.x - othery = self.y - otherreturn Vector02(x, y)def __str__(self):return f"x分量为:{self.x},y分量为{self.y}"v1 = Vector02(1, 2)
v2 = Vector02(3, 4)
v3 = v1 + v2 # v1.__add__(v2)
print(v3.__dict__)
print("v3:",v3)v4 = v1 + 3
print("v4:",v4)v5 = v4 - v1
print("v5:",v5)
print("____")
# 可变数据: +=运算符会返回旧数据 __iadd__
# +运算符返回新数据 __add__
# 对于+=运算符,如果没有__iadd__ ,会自动调用__add__函数,否则优先调用__iadd__函数
v1 = Vector02(1, 1)
print(id(v1)) # 2753663477888
v1 += Vector02(2, 2)
print(id(v1)) # 2753663477888v1 = Vector02(1, 1)
print(id(v1)) # 2753663477888
v1 += 2
print(id(v1)) # 2753663477888
封装案例:
"""疫情信息管理系统V2封装
"""class EpidemicModel:"""数据模型"""def __init__(self, region="", new=0, now=0, total=0, eid=0):self.region = regionself.new = newself.now = nowself.total = totalself.eid = eid # 操作全球唯一标识符的变量class EpidemicView:"""疫情视图"""def __init__(self):self.__controller = EpidemicController()def __display_menu(self):"""显示菜单"""print("按1键录入疫情信息")print("按2键显示疫情信息")print("按3键删除疫情信息")print("按4键修改疫情信息")def __select_menu(self):"""选择菜单"""number = input("请输入选项:")if number == "1":# 重点1:类中通过self调用self.__input_epidemic()elif number == "2":self.__display_epidemics()elif number == "3":self.__delete_epidemic()elif number == "4":self.__modify_epidemic()def __input_epidemic(self):"""录入疫情信息"""# 重点3:每次录入新数据创建新Model对象# model = EpidemicModel(# input("请输入疫情地区:"),# int(input("请输入现有人数:")),# int(input("请输入新增人数:")),# int(input("请输入累计人数:")),# )# model = EpidemicModel(# region=input("请输入疫情地区:"),# now=int(input("请输入现有人数:")),# new=int(input("请输入新增人数:")),# total=int(input("请输入累计人数:")),# )model = EpidemicModel()model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))self.__controller.add_epidemic(model)def __display_epidemics(self):"""显示所有疫情信息"""for item in self.__controller.list_epidemic:print("%s地区的编号是%s,新增%s人,现有%s人,累计%s人" % (item.region, item.eid, item.new, item.now, item.total))def __delete_epidemic(self):"""删除疫情,录入编号,传递给controller,显示结果"""eid = int(input("请输入需要删除的疫情编号:")) # 将输入的编号转为int类型if self.__controller.remove_epidemic(eid):print("删除成功哦~")else:print("哦~不行")def __modify_epidemic(self):"""修改疫情信息,录入、传递、显示:return:"""model = EpidemicModel()model.eid = int(input("请输入需要需改的疫情编号:"))model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))if self.__controller.update_epidemic(model):print("修改成功")else:print("需改失败")def main(self):"""入口哦"""while True:self.__display_menu()self.__select_menu()class EpidemicController:"""疫情控制器"""def __init__(self):self.list_epidemic = [] # type:list[EpidemicModel]self.__start_id = 1001def add_epidemic(self, info):"""添加疫情信息:param info:EpidemicModel类型,新信息"""# 设置自增长编号info.eid = self.__start_idself.__start_id += 1 # 为下一个数据可以使用不同数据# 添加到列表中self.list_epidemic.append(info)def remove_epidemic(self, eid: int):"""在列表中移除疫情信息:param eid: int类型,疫情编号:return: bool类型,True表达移除成功,False表达移除失败"""for i in range(len(self.list_epidemic)):if self.list_epidemic[i].eid == eid:del self.list_epidemic[i]return True # 循环中途退出,返回成功return False # 列表没有找到,则删除失败# remove内部还有层循环,所以带来二次查找# for item in self.list_epidemic:# 列表名.remove(item)def update_epidemic(self, new):"""更新疫情信息:param new: Model类型:return: bool类型"""# for i in range(len(self.list_epidemic)):# self.list_epidemic[i].region = new.regionfor item in self.list_epidemic:if item.eid == new.eid:# item.region = new.region# item.new = new.new# item.now = new.nowitem.__dict__ = new.__dict__return Truereturn Falseview = EpidemicView()
print(view.__dict__)
view.main()
(3)__eq__函数
自定义对象比较相同时,自动执行__eq__函数
如果没有__eq__函数,则默认按地址进行比较
自定义__eq__函数后,进行重写,此时根据内容进行比较
有__eq__函数,结果为True,否则为False
in,count,remove底层都是__eq__函数。
class Vector02:def __init__(self, x ,y):self.x = xself.y = ydef __str__(self):return f"x分量为:{self.x},y分量为{self.y}"# 判断相同def __eq__(self, other):# 默认:按地址比较# return id(self) == id(other)# 重写:按内容比较# if self.x == other.x and self.y == other.y:# return True# return False# 优化重写:按内容比较return self.__dict__ == other.__dict__pos01 = Vector02(1, 1)
pos02 = Vector02(1, 1)
print(pos01 == pos02) # False,两地址不同
# 等价于
print(pos01.__eq__(pos02))# 如果默认有__eq__,则按照内容比较
list01 = [10]
list02 = [10]
print(list01 == list02)list01 = [Vector02(1, 1),Vector02(2, 1),Vector02(3, 1),Vector02(4, 1),Vector02(2, 1),
]# 如果没有__eq__函数,则默认按地址进行比较
# 自定义__eq__函数后,进行重写,此时根据内容进行比较
# 有__eq__函数,结果为True,否则为False
print(Vector02(1, 1) in list01)
# in的内部执行也是使用__eq__函数一一比较
# Vector02(1, 1).__eq__Vector02(1, 1)
# Vector02(2, 1).__eq__Vector02(1, 1)
# Vector02(3, 1).__eq__Vector02(1, 1)
# Vector02(4, 1).__eq__Vector02(1, 1)
# Vector02(2, 1).__eq__Vector02(1, 1)# 有__eq__函数,结果为2,否则为0
print(list01.count(Vector02(2, 1)))
# Vector02(2, 1).__eq__Vector02(1, 1)
# Vector02(2, 1).__eq__Vector02(2, 1)
# Vector02(2, 1).__eq__Vector02(3, 1)
# Vector02(2, 1).__eq__Vector02(4, 1)
# Vector02(2, 1).__eq__Vector02(2, 1)
list01.remove(Vector02(3, 1))
# # Vector02(1, 1).__eq__Vector02(3, 1)
# # Vector02(2, 1).__eq__Vector02(3, 1)
# # Vector02(3, 1).__eq__Vector02(3, 1)
# # list01[3].__eq__Vector02(3, 1)
# # list01[4].__eq__Vector02(3, 1)
(4)__gt__函数
自定义对象比较大小时,自动执行__gt__函数
class Vector02:def __init__(self, x ,y):self.x = xself.y = ydef __str__(self):return f"x分量为:{self.x},y分量为{self.y}"def __eq__(self, other):return self.__dict__ == other.__dict__# 判断大小def __gt__(self, other):# 默认:按地址比较# return id(self) > id(other)# 重写:按内容比较return self.x > other.xpos01 = Vector02(2, 2)
pos02 = Vector02(1, 1)
print(pos01 > pos02) # False,两地址不同list01 = [Vector02(1, 1),Vector02(2, 1),Vector02(3, 1),Vector02(4, 1),Vector02(2, 1),
]print(max(list01))
print(list01.index(Vector02(1, 1))) # index元素索引,没有就会报错
list01.sort() # 升序排列
list01.sort(reverse=True) # 降序排列
for item in list01:print(item)
(4)总结
当打印自定义对象时,自动执行__str__函数
自定义对象相加时,自动执行__add__函数
--通过传入参数的类型决定行为
自定义对象累加时,自动执行__iadd__函数
--可变数据返回旧数据
--不可变数据返回新数据,即自动执行__add__
自定义对象比较相同时,自动执行__eq__函数
自定义对象比较大小时,自动执行__gt__函数
使用重写思路后,案例优化为:
"""疫情信息管理系统V3重写
"""class EpidemicModel:"""数据模型"""def __init__(self, region="", new=0, now=0, total=0, eid=0):self.region = regionself.new = newself.now = nowself.total = totalself.eid = eid # 操作全球唯一标识符的变量def __str__(self):return "%s地区的编号是%s,新增%s人,现有%s人,累计%s人" % (self.region, self.eid, self.new, self.now, self.total)# self是列表中的元素# other参数eiddef __eq__(self, other):return self.eid == otherclass EpidemicView:"""疫情视图"""def __init__(self):self.__controller = EpidemicController()def __display_menu(self):"""显示菜单"""print("按1键录入疫情信息")print("按2键显示疫情信息")print("按3键删除疫情信息")print("按4键修改疫情信息")def __select_menu(self):"""选择菜单"""number = input("请输入选项:")if number == "1":# 重点1:类中通过self调用self.__input_epidemic()elif number == "2":self.__display_epidemics()elif number == "3":self.__delete_epidemic()elif number == "4":self.__modify_epidemic()def __input_epidemic(self):"""录入疫情信息"""# 重点3:每次录入新数据创建新Model对象# model = EpidemicModel(# input("请输入疫情地区:"),# int(input("请输入现有人数:")),# int(input("请输入新增人数:")),# int(input("请输入累计人数:")),# )# model = EpidemicModel(# region=input("请输入疫情地区:"),# now=int(input("请输入现有人数:")),# new=int(input("请输入新增人数:")),# total=int(input("请输入累计人数:")),# )model = EpidemicModel()model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))self.__controller.add_epidemic(model)def __display_epidemics(self):"""显示所有疫情信息"""for item in self.__controller.list_epidemic:# print("%s地区的编号是%s,新增%s人,现有%s人,累计%s人" % (item.region, item.eid, item.new, item.now, item.total))# print(10) # 10.__str__()# print("a") # "a".__str__()print(item) # 打印Model对象,需要重写__str__def __delete_epidemic(self):"""删除疫情,录入编号,传递给controller,显示结果"""eid = int(input("请输入需要删除的疫情编号:")) # 将输入的编号转为int类型if self.__controller.remove_epidemic(eid):print("删除成功哦~")else:print("哦~不行")def __modify_epidemic(self):"""修改疫情信息,录入、传递、显示:return:"""model = EpidemicModel()model.eid = int(input("请输入需要需改的疫情编号:"))model.region = input("请输入疫情地区:")model.new = int(input("请输入新增人数:"))model.now = int(input("请输入现有人数:"))model.total = int(input("请输入累计人数:"))if self.__controller.update_epidemic(model):print("修改成功")else:print("需改失败")def main(self):"""入口哦"""while True:self.__display_menu()self.__select_menu()class EpidemicController:"""疫情控制器"""def __init__(self):self.list_epidemic = [] # type:list[EpidemicModel]self.__start_id = 1001def add_epidemic(self, info):"""添加疫情信息:param info:EpidemicModel类型,新信息"""# 设置自增长编号info.eid = self.__start_idself.__start_id += 1 # 为下一个数据可以使用不同数据# 添加到列表中self.list_epidemic.append(info)def remove_epidemic(self, eid: int):"""在列表中移除疫情信息:param eid: int类型,疫情编号:return: bool类型,True表达移除成功,False表达移除失败"""if eid in self.list_epidemic:self.list_epidemic.remove(eid)return Truereturn False# remove内部源码如下:# for i in range(len(self.list_epidemic)):# if self.list_epidemic[i].__eq__(eid):# del self.list_epidemic[i]def update_epidemic(self, new):"""更新疫情信息:param new: Model类型:return: bool类型"""# for i in range(len(self.list_epidemic)):# self.list_epidemic[i].region = new.regionfor item in self.list_epidemic:if item.eid == new.eid:# item.region = new.region# item.new = new.new# item.now = new.nowitem.__dict__ = new.__dict__return Truereturn Falseview = EpidemicView()
view.main()
MVC架构思路
软件架构设计思路
class Vector2:def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return "x是:%d,y是:%d" % (self.x, self.y)def __add__(self, other):return Vector2(self.x + other.x, self.y +other.yv01 = Vector2(1, 2)
v02 = Vector2(2, 3)
print(v01 + v02) # v01.__add__(v02)
class Vector2:
#二维向量def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return "x是:%d,y是:%d" % (self.x, self.y)# + 创建新def __add__(self, other):return Vector2(self.x + other.x, self.y +other.y)# += 在原有基础上修改(自定义类属于可变对象)def __iadd__(self, other):self.x += other.xself.y += other.yreturn selfv01 = Vector2(1, 2)
v02 = Vector2(2, 3)
print(id(v01))
v01 += v02
print(id(v01))
print(v01)
class Vector2:"""二维向量"""def __init__(self, x, y):self.x = xself.y = y# 决定相同的依据def __eq__(self, other):return self.x == other.x and self.y == other.y# 决定大小的依据def __lt__(self, other):return self.x < other.xv01 = Vector2(1, 1)
v02 = Vector2(1, 1)
print(v01 == v02) # True 比较两个对象内容(__eq__决定)
print(v01 is v02) # False 比较两个对象地址list01 = [
Vector2(2, 2),
Vector2(5, 5),
Vector2(3, 3),
Vector2(1, 1),
Vector2(1, 1),
Vector2(4, 4),
]
# 必须重写 eq
print(Vector2(5, 5) in list01)
print(list01.count(Vector2(1, 1)))
# 必须重写 lt
list01.sort()
print(list01)