7.继承
继承的基础语法
学习目标:理解继承的概念,掌握继承的使用方式,掌握pass关键字的作用
就是把老的设计图继承下来,然后修修改改成为新的设计图
我们可以使用继承,来完成此需求。
单继承
从头写一个新的类:
基于原有的类进行修改:
我们可以通过继承来只关心新的功能,老的功能你压根就不需要关心,只需要通过继承的写法,全部就都过来了
单继承基础语法:
被继承的类我们把它称作父类,继承别人的我们把它称作子类,子类的功能都是从父类那里继承而来的。子类构建的类对象,可以有自己的成员变量和成员方法,使用父类的成员变量和成员方法。
继承分为单继承和多继承。
继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有)
可以看到我在2022里面没有写原来的功能,但是我继承了原来的功能后,也可以直接使用
多继承
单继承是指一个子类继承了一个父类,多继承就表明一个子类它继承了多个父类。
pass只是一个普通的占位语句,没有实际的功能,表示无内容,空的意思,它的作用只是补全我们的语法,让计算机不报错。
多继承的注意事项:多个父类在,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。即:先继承的保留,后继承的被覆盖。
# 演示面向对象:继承的基础语法 # 演示多继承 class Phone: IMEI = None # 序列号 producer = "HM" # 厂商 def call_by_4g(self): print("4g通话") class NFCReader: nfc_type = "第五代" producer = "itcast" def read_card(self): print("NFC读卡") def write_card(self): print("NFC写卡") class RemoteControl: rc_type = "红外遥控" def control(self): print("红外遥控开启了") class MyPhone(Phone,NFCReader,RemoteControl): pass phone = MyPhone() phone.call_by_4g() phone.read_card() phone.write_card() phone.control() print(phone.producer)
谁先来的谁优先级高
复写和调用父类成员
学习目标:掌握复习父类成员的语法,掌握如何在子类中调用父类成员。
复写
对父类的成员属性或成员方法进行重新定义。
就是重新定义一下就可以了
复写的语法:在子类中重新实现同名成员方法或成员属性即可
class Phone: IMEI = None # 序列号 producer = "ITCAST" def call_by_5g(self): print("使用5g网络进行通话") # 定义子类,复写父类成员 class MyPhone(Phone): producer = "itheima" # 复写父类的成员属性 def call_by_5g(self): print("开启CPU单核模式,确保通话得时候省电") print("使用5g网络进行通话") print("关闭CPU单核模式,确保性能") phone = MyPhone() phone.call_by_5g() print(phone.producer)
调用父类同名成员
class Phone: IMEI = None # 序列号 producer = "ITCAST" def call_by_5g(self): print("使用5g网络进行通话") # 定义子类,复写父类成员 class MyPhone(Phone): producer = "itheima" # 复写父类的成员属性 def call_by_5g(self): print("开启CPU单核模式,确保通话得时候省电") # 方式二 print(f"父类的厂商是:{super().producer}") super().call_by_5g() print("关闭CPU单核模式,确保性能") phone = MyPhone() phone.call_by_5g() print(phone.producer)
就是通过调用父类成员的形式,可以拿到被子类所复写的父类里面的内容。
注意:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的。
8.类型注解
变量的类型注解
学习目标:理解为什么使用类型注解,掌握变量的类型注解语法。
就是说:pycharm会确定这是一个什么类型,然后帮助我们推断出来里面有什么方法。
因为pycharm无法通过代码,确定应外部传入什么类型,我们需要使用类型注解。
给变量注释一个类型:
列表、集合类型设置类型详细注解,需要写列表内部是什么类型
容器类型详细注解使用[]
标记黄色下划线只是因为我们在pycharm中标记了重名变量。
这个黄色只是用来提示我们出现重名了。
alt+回车键可以自动搜索导包,帮助我们自动导包
我们可以看到注释中type:后面的int变亮了
# 演示变量的类型注解 import json import random # 基础数据类型注解 var_1:int = 10 # 表示var_1变量里面存储的数据是int整形 var_2:str = "itheima" var_3:bool = True # 类对象类型注解 class Student: pass stu:Student = Student() # 表示stu是Student这个类的类型 # 基础容器类型注解 my_list:list = [1,2,3] my_tuple:tuple = (1,2,3) my_dict:dict = {"itheima":666} # 容器类型详细注解 my_list:list[int] = [1,2,3] my_tuple:tuple[int,str,bool] = (1,"itheima",True) my_dict:dict[str,int] = {"itheima":666} # 在注释中进行类型注解 var_1 = random.randint(1,10) # type:int var_2 = json.loads('{"name":"zzzz"}') # type:dict[str,str] def func(): return 10 var_3 = func() # type:int # 类型注解的限制 var_4:int = "ikun" var_5:str = 123
类型注解其实仅仅只是一个备注,它压根不会影响到我们程序的运行,所以你哪怕标记错了也没有关系
总结:
函数(方法)的类型注解
学习目标:掌握为函数(方法)形参进行类型注解,掌握为函数(方法)返回值进行类型注解
这个注解都不是强制性的,只是建议性的。
总结
-> 这就是一个减号和一个大于号
Union类型
学习目标:理解Union类型,掌握使用Union进行联合类型注解
使用Union[类型,......,类型]
可以定义联合类型注解
总结:
记得导包,U大写,中括号[]
9.多态
学习目标:理解多态的概念,理解抽象类(接口)的编程思想
使用同样的函数(行为),给他传入不同的对象,你就得到不同的状态了
# 演示面向对象的多态特性以及抽象类(接口)的使用 class Animal: def speak(self): pass class Dog(Animal): def speak(self): print("汪汪汪") class Cat(Animal): def speak(self): print("喵喵喵") def make_noise(animal:Animal): # 制作点噪音,需要传入Animal对象 animal.speak() # 演示多态,使用2个子类对象来调用函数 dog = Dog() cat = Cat() make_noise(dog) make_noise(cat)
抽象类其实就是用来做顶层设计,但是我们并不直接使用AC,也就是并不直接使用抽象类,而是使用他的具体子类
这也是强制要求我们子类必须复写父类,不然全是空,无法使用
class AC: def cool_wind(self): """制冷""" pass def hot_wind(self): """制热""" pass def swing_l_r(self): """左右摆风""" pass class Midea_AC(AC): def cool_wind(self): print("美的空调制冷") def hot_wind(self): print("美的空调制热") def swing_l_r(self): print("美的空调左右摆风") class GREE_AC(AC): def cool_wind(self): print("格力空调制冷") def hot_wind(self): print("格力空调制热") def swing_l_r(self): print("格力空调左右摆风") def make_cool(ac:AC): ac.cool_wind() midea_ac = Midea_AC() gree_ac = GREE_AC() make_cool(midea_ac) make_cool(gree_ac)
我们可以实现做顶层设计也就是标准,然后由具体的类去实现,同时呢也能够完成同一种行为不同的运行状态了。
总结
(1)什么是多态?
多态指的是,同一种行为,使用不同的对象获得不同的状态。如:定义函数(方法),通过类型注解声明需要父类对象,实际传入子类对象进行工作,从而获得不同的工作状态。
(2)什么是抽象类(接口)?
包含抽象方法的类,称之为抽象类。抽象方法是指:没有具体实现的方法(pass)称之为抽象方法。
(3)抽象类的作用
多用于做顶层设计(设计标准),以便子类做具体实现。也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法,并配合多态使用,获得不同的工作状态。
10.综合案例(数据分析的案例)
学习目标:使用面向对象思想完成数据读取和处理,基于面向对象思想重新认知第三方库使用(PyEcharts)
只需要把每一天的销售额拿过来,求个和就可以了
实现步骤: 1.设计一个类,可以完成数据的封装 2.设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能 3.读取文件,生产数据对象 4.进行数据需求的逻辑计算(计算每一天的销售额) 5.通过PyEcharts进行图形绘制
文件读取
由于文件格式不同,我们读取它的具体实现,它的逻辑是不是也不一样,所以我们需要去构建一个抽象类,先在最顶级我们设计好读取文件应该有哪些基础功能,但我们不实现,然后我们通过具体的子类,比如说文本读取的子类或者json读取的子类,来去实现具体数据的具体读取方法
写一部分检查一下,你会发现中间空了一个,因为每一行有一个\n,你直接print这个\n就会出现换行
line = line.strip() 加入这行代码,删除\n即可
数据统计
假设有一个字典,字典里面记录的有key和value,我们的key就是日期,比如是2011年1月1日,这个key,然后记录的value,可能是它的今天的销售额,我们可以通过for循环,挨个取它里面的数据,如果取到的某一个Record里面的日期呢,是1月1号,就到字典里面看一看有没有1月1号这个key,如果有的话,就把记录的这个销售额和我当前记录的进行一个累加,然后继续for循环,出现1月1号就把它加起来,那如果我们取到的是1月2号这个key不存在,我们就给它里面再加一个新key,然后值就是你当前取到这个Record里面记录的,然后继续循环,遇到1月2号就累加......
字典的key是不会重复的,就可以判断里面有没有key,有的话就表明你已经有累加的记录了,直接把当前值给你累加上去,如果没有的话,那表明我是当前这个日期的第一条,然后把我当前的数据放进去。
统计出了每一天的销售额
可视化开发
依旧是之前构建动态柱状图的方法
if __name__ == '__main__':
这段代码意思是后面的代码只在本文件中有效,别的文件导包这个文件无效
相信大家思路都差不多了,接下来看代码!
完整代码
# 数据定义的类 class Record: # 用来记录数据的基本信息 def __init__(self,date,order_id,money,province): self.date = date # 订单日期 self.order_id = order_id # 订单id self.money = money # 订单金额 self.province = province # 销售省份 def __str__(self): return f"{self.date},{self.order_id},{self.money},{self.province}"
""" 和文件相关的类定义 """ from data_define import Record import json # 先定义一个抽象类用来做顶层设计,确定有哪些功能需要实现 class FileReader: def read_data(self) -> list[Record]: """读取文件的数据,读到的每一条数据都转换为Record对象,将它们都封装到list内返回即可""" pass class TexFileReader(FileReader): def __init__(self,path): self.path = path # 定义成员变量记录文件的路径 # 复写(实现抽象方法)父类的方法 def read_data(self) -> list[Record]: f = open(self.path,"r",encoding="UTF-8") record_list:list[Record] = [] for line in f.readlines(): line = line.strip() # 消除读取到的每一行数据中的\n data_list = line.split(",") record = Record(data_list[0],data_list[1],int(data_list[2]),data_list[3]) record_list.append(record) f.close() return record_list class JsonFileReader(FileReader): def __init__(self,path): self.path = path # 定义成员变量记录文件的路径 # 复写(实现抽象方法)父类的方法 def read_data(self) -> list[Record]: f = open(self.path, "r", encoding="UTF-8") record_list: list[Record] = [] for line in f.readlines(): data_dict = json.loads(line) record = Record(data_dict["date"], data_dict["order_id"], data_dict["money"], data_dict["province"]) record_list.append(record) f.close() return record_list if __name__ == '__main__': text_file_reader = TexFileReader("D:/2011年1月销售数据(1)(1).txt") json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON(2).txt") list1 = text_file_reader.read_data() list2 = json_file_reader.read_data() for l in list1: print(l) for h in list2: print(h)
# 面向对象,数据开发案例,主业务逻辑代码 """ 实现步骤: 1.设计一个类,可以完成数据的封装 2.设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能 3.读取文件,生产数据对象 4.进行数据需求的逻辑计算(计算每一天的销售额) 5.通过PyEcharts进行图形绘制 """ from file_define import FileReader,JsonFileReader,TexFileReader from data_define import Record from pyecharts.charts import Bar from pyecharts.options import * from pyecharts.globals import ThemeType text_file_reader = TexFileReader("D:/2011年1月销售数据(1)(1).txt") json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON(2).txt") jan_data:list[Record] = text_file_reader.read_data() # 一月份数据 feb_data:list[Record] = json_file_reader.read_data() # 二月份数据 # 将2个月份的数据合并为1个list来存储 all_data:list[Record] = jan_data + feb_data # 开始进行数据计算 data_dict = {} for record in all_data: if record.date in data_dict.keys(): # 当前日期已经有记录了,所以和老记录做累加即可 data_dict[record.date] += record.money else: data_dict[record.date] = record.money # 可视化图表开发 bar = Bar(init_opts=InitOpts(theme=ThemeType.LIGHT)) # 设置主题颜色 bar.add_xaxis(list(data_dict.keys())) # 添加x轴数据 bar.add_yaxis("销售额",list(data_dict.values()),label_opts=LabelOpts(is_show=False)) # 添加y轴数据 让数据不显示 bar.set_global_opts( title_opts=TitleOpts(title="每日销售额") ) bar.render("每日销售额柱状图.html")