目录
1. 封装
1.1 私有成员:__成员、__成员方法
2. 继承:单继承、多继承
2.1 继承的基础语法
2.2 复写 & 子类使用父类成员
3. 变量的类型注解:给变量标识变量类型
3.1 为什么需要类型注解
3.2 类型注解
3.3 类型注解的语法
3.4 类型的注解限制
4. 函数和方法类型的注解:给函数和方法标识数据类型
4.1 函数(方法)的类型注解-形参注解
4.2 函数(方法)的类型注解-返回值注解
5. Union联合类型注解:给变量、函数和方法、形参和返回值标识联合类型注解
5.1 Union概念
5.2 Union使用
6. 多态
6.1 多态使用
6.2 抽象类(接口)
7. 案例:使用面向对象概念实现
7.1 数据分析案例-文件读取
7.2 数据分析案例-数据计算
7.3 数据分析案例-可视化开发
导航:
Python第二语言(一、Python start)-CSDN博客
Python第二语言(二、Python语言基础)-CSDN博客
Python第二语言(三、Python函数def)-CSDN博客
Python第二语言(四、Python数据容器)-CSDN博客
Python第二语言(五、Python文件相关操作)-CSDN博客
Python第二语言(六、Python异常)-CSDN博客
Python第二语言(七、Python模块)-CSDN博客
Python第二语言(八、Python包)-CSDN博客
Python第二语言(九、Python第一阶段实操)-CSDN博客
Python第二语言(十、Python面向对象(上))-CSDN博客
Python第二语言(十一、Python面向对象(下))-CSDN博客
Python第二语言(十二、SQL入门和实战)-CSDN博客
Python第二语言(十三、PySpark实战)-CSDN博客
Python第二语言(十四、高阶基础)-CSDN博客
面向对象编程,是许多编程语言都支持的一种编程思想;
基本思想:基于模板(类)去创建实体(对象),使用对象完成功能开发;
1. 封装
- 封装表示的是,将现实世界事物的:属性、行为,封装到类中,描述位成员变量和成员方法;
- 对用户隐藏的属性和行为:比如电视机的外壳,内部就封装了我们用户看不见的电线;
1.1 私有成员:__成员、__成员方法
既然现实事务由不公开的属性和行为,那么作为现实事务在程序中映射的类,也应该支持;
类中提供了私有成员的形式来支持:私有成员变量、私有成员方法;
-
定义私有成员的方式:
私有成员变量:变量名以__开头(2个下划线)
私有成员方法:方法名以__开头(2个下划线)
1. 私有方法无法直接被类对象使用,私有变量无法赋值,也无法获取值;
class phone:IMEI = None # 序列号producer = None # 厂商__current_voltage = None # 私有:当前私有属性def call_by_5g(self):print("5G通话已开启")def __keep_single_core(self): # 私有:当前私有方法print("让CPU以单核模式运行以节省电量")phone = Phone() # 创建对象
phone.__keep_single_core() # 使用私有方法,无法使用
phone.__current_voltage = 220 # 私有变量赋值
print(phone.__current_voltage) # 获取私有变量,无法使用
2. 成员变量的使用;
使用公共方法来访问类的私有属性;在类的内部其他成员可以随便使用类的私有属性或方法;
class phone:__current_voltage = None # 私有:当前私有属性def __keep_single_core(self): # 私有:当前私有方法print("让CPU以单核模式运行以节省电量")def call_by_5g(self):if self.__current_voltage() >= 1: # 可以使用私有成员print("5G通话已开启")else:self.__keep_single_core()print("无法使用5G通话")
小结:
-
为什么是私有成员,为什么需要私有成员?
现实事务有部分属性和行为是不公开对使用者开放的,同样在类中描述属性和方法的时候也需要达到这个要求,就需要定义私有变量成员了;
-
如何定义私有成员:成员变量和成员方法的命名以_ _开头即可;
-
私有成员的访问限制:类对象无法访问私有成员,类中的其他成员可以访问私有成员;
-
对类封装私有的类的内部成员,不对外开放,实现封装的概念;
-
如没必要的私有方法或属性,没必要展示给用户看,或没必要给程序员调用该私有方法或私有属性;
2. 继承:单继承、多继承
2.1 继承的基础语法
- 继承的引出:由一代代不断迭代的产品中,基于老款的设计图,进行修改;
- 继承分为:单继承和多继承;
- 继承表示:将从父类那里继承(复制)来成员变量和方法(不包含私有的)
1. 继承的写法:class 子类(继承的父类):
2. 单继承class 子类(父类)
- 继承别的类的叫做子类,被继承的叫做父类;
实现单继承:
class Phone: # 单继承IMEI = Noneproducer = "HW"def call_by_4g(self):print("4g通话")class Phone2024(Phone):face_id = "10001"def call_by_5g(self):print("2024开始5g通话")phone = Phone2024()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
3. 多继承class 子类(父类1, 父类2, 父类3)
- 由单个子类继承多个父类,实现所有继承父类的公共方法和公共属性;
pass
语法:代表这是空的,这里什么都没有,让代码不报错;- 多继承的注意事项:如果父类中存在同名的属性怎么办?会默认按照继承顺序从左到右为优先级调用;
class Phone: # 单继承IMEI = Noneproducer = "HW"def call_by_4g(self):print("4g通话")class MIUIPhone:def read_card(self):print("小米手机,贴近生活")class HuaweiPhone:def control(self):print("华为手机,值得拥有")class Phone2024(Phone, MIUIPhone, HuaweiPhone): # 多继承passphone = Phone2024()
phone.call_by_4g() # 1.继承手机
phone.read_card() # 2.继承小米手机
phone.control() # 3.继承华为手机
小结:
- 继承就是一个类继承另外一个类的成员变量和方法;
- 语法
class 子类(父类1, 父类2, ...)
- 子类构建的类对象:可以有自己的成员变量和成员方法;子类可以使用父类的成员变量和方法;
- 语法
- 单继承和多继承:
- 单继承:一个类继承另一个类;
- 多继承:一个类继承多个类,按照顺序从左往右依次继承;
- 多继承中,如果父类有同名的方法或属性,先继承的优先级高于后继承;
2.2 复写 & 子类使用父类成员
1. 复写:就是单纯的在子类中重写父类的属性和方法,实现复写(一般都是子类继承父类后,需求不满足,那么可以进行复写);
class Phone:IMEI = Nonedef call_by_5g(self):print("父类5g通话")class Phone2024(Phone):IMEI = "10001" # 复写父类属性def call_by_5g(self): # 复写父类方法print("子类重写5g通话,视频通话")phone = Phone2024()
phone.call_by_5g()
2. 子类中调用父类成员
- 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员,如果想要使用被复写的父类成员,就需要特殊的调用方式;
- 调用父类成员:
- 使用成员变量:
父类名.成员变量
- 使用成员方法:
父类名.成员方法(self)
- 使用成员变量:
- 使用super()调用父类成员:
- 使用成员变量:
super().成员变量
- 使用成员方法:
super().成员方法()
- 通过
super父类().方法或属性
直接调用,且调用方法时不用加上self
;
- 使用成员变量:
class Phone:IMEI = Noneproduct = "苹果手机"def call_by_5g(self):print("父类5g通话")class Phone2024(Phone):IMEI = "10001"product = "华为手机"def call_by_5g(self):print(f"父类的产品是:{Phone.product}") # 1.调用父类属性Phone.call_by_5g(self) # 2.调用父类属性# print("子类重写5g通话,视频通话")print(f"父类的产品是:{super().product}") # 3.调用父类属性super(Phone2024, self).call_by_5g() # 4.调用父类方法 或 super().call_by_5g()phone = Phone2024()
phone.call_by_5g()
小结:
- 复写表示:对父类的成员属性或成员方法进行重写定义;
- 复写的语法:在子类中重新实现同名成员方法或成员属性即可;
3. 变量的类型注解:给变量标识变量类型
3.1 为什么需要类型注解
(就是开发工具无法识别到自定义的方法中的参数类型,在编写代码时无方法提示参数类型)还有可以清晰明了变量的类型;
前者有解释说要传递一个int类型的参数;
而后者只告诉了我们传递的参数名是data,并不知道是什么类型的参数;
3.2 类型注解
-
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具;
-
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明);
-
主要功能:
帮助第三方IDE工具(如PyCharm,IDEA)对代码进行类型推断,协助做代码提示;
帮助开发者自身对变量进行类型注释;
-
支持:
变量的类型注解;
函数(方法)形参列表和返回值的类型注解;
3.3 类型注解的语法
1. 基础类型注解:var_1: int = 10
- 基础类型注解一般可以不写,写的情况是无法一眼看出变量类型的时候写入;
# 基础数据类型注解
var_1: int = 10
var_2: float = 3.1415926
var_3: bool = True
var_4: str = "zhangSan"# 类对象类型注解
class Student:passstu: Student = Student()
2. 容器类型注解:my_tuple: tuple = (1, 2, 3) || my_tuple: tuple[str, int, boll] = ("xxx", 88, True) 比较常用
- 可以对容器类型继续标记类型,以及对容器中内部进行标记类型;
- 基础容器类型注解;
- 容器类型详细注解;
# 基础容器类型注解
my_listL: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {"age": 3}
my_str: str = "zhangSan"# 容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple1: tuple[str, int, bool] = ("zhangSan", 88, True) # 元组类型设置类型详细注解,需要将每一个元素都标记出来
my_set1: set[int] = {1, 2, 3}
my_dict1: dict[str, int] = {"age": 120} # 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
3. 注释标记变量类型var_1 = random.randint(1, 10) # type: int
除了使用变量:类型
,这种语法做注解外,也可以在注释中进行类型注解;
语法:# type:类型
3.4 类型的注解限制
- 类型标记错误,开发工具中都会有提示;
- 预期的是int类型,但是具体得到的类型是str类型;
- 类型注解主要功能在于:
- 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示;
- 帮助开发者自身对变量进行类型注释(备注);
- 并不会真正的对类型做验证和判断,也就是类型注解仅仅是提示,并不能决定程序的走向;
4. 函数和方法类型的注解:给函数和方法标识数据类型
- 在函数中定义的类型,只是提示性的,并非决定性的,就是执行过程中,类型输入不正确也不会报错;
4.1 函数(方法)的类型注解-形参注解
def func(data):passdef func1(name: str, score: tuple): # 形参名:类型,形参名:类型,...passfunc(data=1)
func1("zhangSan", (80, 100, 90))
4.2 函数(方法)的类型注解-返回值注解
函数的型参可以加类型,其函数返回值也可以添加类型注解;
语法:
def 函数方法名(形参: 类型, ..., 形参: 类型) -> 返回值类型:pass
def func(data: list) -> list:return datafunc()
5. Union联合类型注解:给变量、函数和方法、形参和返回值标识联合类型注解
5.1 Union概念
使用Union解决无法确认的类型情况:
如果是list中,出现不规则的数据类型,那么无法之前的类型注解去确认数据的类型,而是可以采用Union来表示,list中包含的数据类型:my_list: list[Union[str, int]] = [1, 2, "xxx", "xxx"]
;
字典的key: value
也是一样,可以用Union
注解来标识,这个key或value中可以包含什么样的数据类型;
5.2 Union使用
- 使用方式:
from typing import Union
- 使用:
Union[类型, ..., 类型]
其他类型也可以使用Union类型注解,函数(方法)、形参和返回值注解
中都可以;
# 使用Union类型,必须导入Union包
from typing import Union# 作用在基础类型上
my_list: list[Union[int, str]] = [1, 2, "zhangSan", "lisi"]# 作用在函数上
def func(data: Union[int, str]) -> Union[int, str]:passfunc(data=1)
func(data="zhangSan")
6. 多态
6.1 多态使用
- 多态抽象概念:一个设计方法,里面是空的,但是定义了标准的格式,需要有具体的实现,而实现可以有多种,可以随意调用某个实现类,这就是多态;
- 或者说:多态,就是多种状态,即完成某个行为时,使用不同的对象会得到不同的状态;
- 多态常作用在继承关系上;
- 比如:
- 函数(方法)形参声明接收父类对象;
- 实际传入父类的子类对象进行工作;
- 即:
- 以父类做定义声明;
- 以子类做实际工作;
- 用以获得同一行为,不同状态;
class Animal:def speak(self):passclass Dog(Animal):def speak(self):print("wang wang wang")class Cat(Animal):def speak(self):print("miao miao miao")def make_noise(animal: Animal): # 多态的使用animal.speak()dog = Dog()
cat = Cat()
make_noise(dog)
make_noise(cat)
6.2 抽象类(接口)
1. 抽象类(接口概念)配合多态使用:
-
这种设计的含义是:
- 父类用来确定有哪些方法;
- 具体的方法实现,由子类自行决定;
-
抽象类(也可以称为接口)
-
抽象类:含有抽象方法的类称之为抽象类,无具体实现;
-
抽象方法:方法体是空实现的(pass)称之为抽象方法;
-
概念:抽象类就好比定义一个标准;包含了一些抽象方法,要求子类必须实现;
-
一般抽象类会配合多态实现:
- 抽象的父类设计(设计标准)
- 具体的子类实现(实现标准)
2. 案例:
大致就是,定义一个抽象类(接口):只有方法,没有实现,而子类去实现抽象类,子类继承接口,去实现接口中的方法,而定义一个单独的调用类,将接口作为新参传递,调用类具体的使用,是由继承接口的是实现类作为参数传递,去使用;传递的是哪个实现类,那么就可以用哪个实现的方法,从而统一方法;
小结:
- 什么是多态:
- 同一行为,不同对象获得不同的状态;
- 什么是抽象类(接口):
- 包含抽象方法的类,称之为抽象类;
- 抽象方法:没有具体的实现方法(pass);
- 抽象类的作用:
- 多用于做顶层设计(设计标准),以便子类做具体实现;
- 对子类有一种软性约束,要求子类必须复写(实现)父类的一些方法;
- 一般配合多态使用,获得不同的工作状态;
7. 案例:使用面向对象概念实现
- 案例:使用面向对象概念实现;
- 使用面向对象思想完成数据读取和处理;
- 基于面向对象思想重新认知第三方库使用(PyEcharts);
7.1 数据分析案例-文件读取
- 实现第一步和第二步;
- 需求:对2份数据文件,进行计算每日的销售额并以柱状图表的形式进行展示;
1. 数据内容:
2024年6月数据:
2024-06-01,0184042c5eff11eda948fa163e3ae10e,1980,浙江省
2024-06-01,01849af15eff11eda948fa163e3ae10e,1980,安徽省
2024-06-01,01849bf75eff11eda948fa163e3ae10e,1980,河南省
2024-06-01,01849c4f5eff11eda948fa163e3ae10e,1980,四川省
2024年7月销售数据JSON:
{"date":"2024-07-01","order_id":"0184042c5eff11eda948fa163e3ae10e","money":1805,"province":"浙江省"}
{"date":"2024-07-01","order_id":"01849af15eff11eda948fa163e3ae10e","money":1999,"province":"安徽省"}
{"date":"2024-07-01","order_id":"01849bf75eff11eda948fa163e3ae10e","money":2025,"province":"河南省"}
{"date":"2024-07-01","order_id":"01849c4f5eff11eda948fa163e3ae10e","money":1685,"province":"四川省"}
{"date":"2024-07-02","order_id":"0184042c5eff11eda948fa163e3ae10e","money":1800,"province":"浙江省"}
{"date":"2024-07-02","order_id":"01849af15eff11eda948fa163e3ae10e","money":1586,"province":"安徽省"}
{"date":"2024-07-02","order_id":"01849bf75eff11eda948fa163e3ae10e","money":1950,"province":"河南省"}
{"date":"2024-07-02","order_id":"01849c4f5eff11eda948fa163e3ae10e","money":2600,"province":"四川省"}
- 1月份数据是普通文本,使用逗号分割数据记录,从前到后分别是(日期,订单id,销售额,销售省份)
- 2月份份数据是JSON数据,同样包含(日期,订单id,销售额,销售省份)
2. 需求分析:
- 读取数据:设计FileReader类;
- 封装数据对象:设计数据封装类;
- 计算数据对象:对对象进行逻辑计算;
- pyecharts绘图:以面向对象思想重新认知pyecharts;
3. 具体实现:
第一步:定义数据分析类(完成数据封装)
"""
数据定义类
"""class Record:def __init__(self, date, order_id, money, province):self.date = date # 订单日期self.order_id = order_id # 订单IDself.money = money # 订单金额self.province = province # 销售省份def __str__(self) -> str:return f"{self.date}, {self.order_id}, {self.money}, {self.province}"
第二步:文件读取抽象类,确定需要的功能,比如读取字符串,读取JSON
- 提示:
- 在该代码上加上类型转换;
"""
文件相关的类定义
"""
import jsonfrom data_define import Record# 定义抽象类做顶层设计,确认功能需求实现
class FileReader:def read_data(self) -> list[Record]:""" 读取文件的数据,读到的每一条转换为Record对象,并封装为list返回 """pass# 实现类
class TextFileReader(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() # 消除读取到每一行的数据中的\ndata_list = line.split(",") # 根据逗号,分割record = Record(data_list[0], data_list[1],data_list[2], data_list[3]) # 将读取文件的数据赋值给对象record_list.append(record)print(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["data"], data_dict["order_id"],data_dict["money"], data_dict["province"]) # 将读取文件的数据赋值给对象record_list.append(record)f.close()return record_listif __name__ == '__main__':text_file_reader = TextFileReader("../file/2024年6月数据")data = text_file_reader.read_data()print(data)
内容调用输出:
定义实现类对象,并且传递文件读取路径,而实现类返回的是list对象,对象中去循环打印文件读取出来的list,并有了str魔术方法,以字符串构建;
if __name__ == '__main__':text_file_reader = TextFileReader("../file/2024年6月数据")json_file_reader = JsonFileReader("../file/2024年7月销售数据JSON")data = text_file_reader.read_data()data1 = json_file_reader.read_data()for li in data:print(li)for li in data1:print(li)
7.2 数据分析案例-数据计算
提示:list合并:list3 = list01 + list02
数据计算:
from file_define import FileReader, TextFileReader, JsonFileReader
from data_define import Recordtext_file_reader = TextFileReader("../file/2024年6月数据")
json_file_reader = JsonFileReader("../file/2024年7月销售数据JSON")jan_data: list[Record] = text_file_reader.read_data()
feb_data: list[Record] = json_file_reader.read_data()# 将2各月份的数据合并
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.moneyelse:data_dict[record.date] = record.money
print(data_dict)
7.3 数据分析案例-可视化开发
from file_define import FileReader, TextFileReader, JsonFileReader
from data_define import Record
# 可视化图标开发
from pyecharts.options import InitOpts, LabelOpts, TitleOpts
from pyecharts.charts import Timeline, Bar
from pyecharts.globals import ThemeTypetext_file_reader = TextFileReader("../file/2024年6月数据")
json_file_reader = JsonFileReader("../file/2024年7月销售数据JSON")jan_data: list[Record] = text_file_reader.read_data()
feb_data: list[Record] = json_file_reader.read_data()# 将2各月份的数据合并
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.moneyelse:data_dict[record.date] = record.money
# print(data_dict)bar = Bar(init_opts=InitOpts(theme=ThemeType.LIGHT))
bar.add_xaxis(list(data_dict.keys()))
bar.add_yaxis("销售额", list(data_dict.values()), label_opts=LabelOpts(is_show=False))
bar.set_global_opts(title_opts=TitleOpts(title="每日销售额")
)
bar.render("每日销售额柱状图.html")