参考视频
初识对象
# 班级中组织个人信息,每个人提交上来的信息千差万别,但是老师设计打印一样的表格
# 让学生填写,填写完后就比较规范一目了然。
# 使用对象组织数据
# 在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的。
# 1.在程序中设计表格,我们称之为:设计类(class)
# class Student:
# name = None # 记录学生姓名
# 2.在程序中打印生产表格,我们称之为:创建对象
# # 基于类创建对象
# stu_1= Student()
# stu_2= Student()
# 3.在程序中填写表格,我们称之为:对象属性赋值
# stu_1.name = "周杰轮" #为学生1对象赋子名称属性值
# stu_2.name = "林军杰" #为学生2对象赋予名称属性值
# 基于类来创建对象
# 1、设计一个类(类比生活中:设计一个登记表)
class Student:
name = None # 记录学生姓名
gender = None # 记录学生性别
nationality = None # 记录学生国籍
native_place = None # 记录学生籍贯
age = None # 记录学生年龄
# 2、创建一个对象(类比生活中:填写表单)
stu_1 = Student() # stu_1既是变量又是Student()这个类的对象
# 3、对象属性进行赋值(类比生活中:填写表单)
stu_1.name = '林俊杰' # 记录学生姓名
stu_1.gender = '男' # 记录学生性别
stu_1.nationality = '中国' # 记录学生国籍
stu_1.native_place = '山东省' # 记录学生籍贯
stu_1.age = '31' # 记录学生年龄
# 4、获取对象中记录的信息
print(stu_1.name)
print(stu_1.gender)
print(stu_1.nationality)
print(stu_1.native_place)
print(stu_1.age)
"""
林俊杰
男
中国
山东省
31
"""
类的成员方法
# 类(class)不仅可以定义属性用来记录数据,也可以定义函数,用来记录行为
# 其中,类中定义的属性(变量),我们称之为:成员变量
# 类中定义的行为(函数),我们称之为:成员方法
# 所说的函数是定义在类外部的函数
# 所说的方法是类内部的函数,即类内部的函数是指方法
# 成员方法的定义语法
# 在类中定义成员方法和定义函数基本一致,但仍有细微区别:
# def 方法名(self,形参1,......,形参N): 方法体
#
# 可以看到,在方法定义的参数列表中,有一个:self关键字
# self关键字是成员方法定义的时候,必须填写的。
# ·它用来表示类对象自身的意思
# ,当我们使用类对象调用方法的是,self会自动被python传入
# ·在方法内部,想要访问类的成员变量,必须使用self
# 定义一个带有成员方法的类
class Student: # 类的名称,采用Pascal命名法如UserAccount,CustomerOrder大写,而下划线命名法如user_name适用于命名变量。
name = None # 定义成员变量,学生的姓名
# self表示类对象本身的意思,只有通过self,成员方法才能访问类的成员变量,
# self出现在形参列表中,但是不占用参数位置,无需理会
def say_hi(self): # 定义成员方法,self必须要在该形式传参列表中,self总是指调用时的类的实例。
print(f'大家好,我是{self.name},多多关照') # 想在成员方法中访问成员变量需要带上self.
def say_hi2(self, msg): # msg接收一个传入参数,新的打招呼方式
print(f'大家好,我是{self.name},{msg}') # 想要访问成员属性name必须用self,而msg是外部传入的可以直接用
stu = Student() # 定义类对象,把类构建一个具体的类对象来使用,变量stu接收Student()类对象
stu.name = '周杰伦' # 使用stu类对象就可以使用成员方法name变量并赋一个值
stu.say_hi() # 调用成员方法(类似调用函数),调用时可以不用传任何东西
stu.say_hi2('哎呦不错呦')
stu2 = Student()
stu2.name = '林俊杰'
stu2.say_hi()
stu2.say_hi2('不该沉默时沉默')
"""
大家好,我是周杰伦,多多关照
大家好,我是周杰伦,哎呦不错呦
大家好,我是林俊杰,多多关照
大家好,我是林俊杰,不该沉默时沉默
"""
# 定义一个带有成员方法的类
class Student: # 类的名称,采用Pascal命名法如UserAccount,CustomerOrder大写,而下划线命名法如user_name适用于命名变量。
name = None # 定义成员变量,学生的姓名
msg = None
# self表示类对象本身的意思,只有通过self,成员方法才能访问类的成员变量,
# self出现在形参列表中,但是不占用参数位置,无需理会
def say_hi(self): # 定义成员方法,self必须要在该形式传参列表中,self总是指调用时的类的实例。
print(f'大家好,我是{self.name},{self.msg}') # 想在成员方法中访问成员变量需要带上self.
def say_hi2(self): # msg接收一个传入参数,新的打招呼方式
print(f'大家好,我是{self.name},{self.msg}') # 想要访问成员属性name必须用self,而msg是外部传入的可以直接用
stu = Student() # 定义类对象,把类构建一个具体的类对象来使用,变量stu接收Student()类对象
stu.name = '周杰伦' # 使用stu类对象就可以使用成员方法name变量并赋一个值
stu.msg = '哎呦不错呦'
stu.say_hi() # 调用成员方法(类似调用函数),调用时可以不用传任何东西
stu.say_hi2()
stu2 = Student()
stu2.name = '林俊杰'
stu2.msg = '不该沉默时沉默'
stu2.say_hi()
stu2.say_hi2()
类和对象
# 现实事物归纳为两个特征:属性和行为
# 基于类创建对象的语法:对象名 = 类名称()
# 类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作
# 面向对象编程:设计类,基于类创建对象,由对象做具体的工作
# 设计一个闹钟类
class Clock:
id = None # 序列化
price = None # 价格
def ring(self):
import winsound
winsound.Beep(2000, 3000) # 发声频率和时间
# 构建2个闹钟对象并让其工作。多少个对象都可以,干活的是clock1,clock2…………
clock1 = Clock()
clock1.id = '003032'
clock1.price = 19.99
print(f'闹钟ID:{clock1.id}, 价格:{clock1.price}')
clock1.ring()
"""
闹钟ID:003032, 价格:19.99(然后响铃)
"""
class Clock:
id = None # 序列化
price = None # 价格
def ring(self, x, y):
ring_result = x + y
print(f'The clock is ringing! Result: {ring_result}')
# 构建2个闹钟对象并让其工作。多少个对象都可以,干活的是clock1,clock2…………
clock1 = Clock()
clock1.id = '003032'
clock1.price = 19.99
print(f'闹钟ID:{clock1.id}, 价格:{clock1.price}')
clock1.ring(1, 2)
"""
闹钟ID:003032, 价格:19.99
The clock is ringing! Result: 3
"""
构造方法
"""
构造方法:
Python类可以使用:__init__()方法,称之为构造方法。
可以实现:
在创建类对象(构造类)的时候,会自动执行。
在创建类对象(构造类)的时候,将传入参数自动传递给_init_方法使用。
"""
# 构造方法的名称:__init__
class Student:
name = None # 成员变量定义可不写
age = None # 成员变量定义可不写
tel = None # 成员变量定义可不写
def __init__(self, name, age, tel):
self.name = name # 既有赋值的功能,又要定义的功能
self.age = age
self.tel = tel
print('Student类创建了一个类对象')
stu = Student('周杰伦', 31, '18500006666')
print(stu.name)
print(stu.age)
print(stu.tel)
"""
Student类创建了一个类对象
周杰伦
31
18500006666
"""
构造方法案例
# 开学了有一批学生信息需要录入系统,请设计一个类,记录学生的:
# 姓名、年龄、地址,这3类信息
#
# 请实现:
# ·通过for循环,配合input输入语句,并使用构造方法,完成学生信息的键盘录入
# ·输入完成后,使用print语句,完成信息的输出
#
# 当前录入第1位学生信息,总共需录入10位学生信息
# 请输入学生姓名:周杰轮
# 请输入学生年龄:31
# 请输入学生地址:北京
# 学生1的信息录入完成,信息为:【学生姓名:周杰轮,年龄:31,地址:北京】
# 当前录入第2位学生信息,总共需录入10位学生信息
# 请输入学生姓名:
# 自己的方法
# i = 1 # 循环中已经初始化了,无序赋值
for i in range(1, 11):
class Student:
name = None # 成员变量定义可不写
age = None # 成员变量定义可不写
addr = None # 成员变量定义可不写
def __init__(self, name, age, addr):
self.name = name # 既有赋值的功能,又要定义的功能
self.age = age
self.addr = addr
print(f'当前录入第{i}位学生信息,总共需录入10位学生信息')
stu = Student(name=input(f'请输入学生的姓名:'), age=input(f'请输入学生的年龄:'), addr=input(f'请输入学生的地址:'))
print(f'学生{i}信息录入完成,信息为:【学生姓名:{stu.name},年龄:{stu.age},地址:{stu.addr}】')
构造方法案例GPT结果
"""
在这个版本中,我将 name、age 和 addr 修改为 student_name、student_age 和 student_addr,
以避免与 __init__ 方法中的参数名称冲突。这样就不会再出现外部作用域隐藏名称的警告。
"""
class Student:
def __init__(self, student_name, student_age, student_addr):
self.name = student_name
self.age = student_age
self.address = student_addr
# 创建一个空列表,用于存储学生对象
students_list = []
# 使用 for 循环录入 10 位学生信息
for i in range(1, 11):
print(f'当前录入第{i}位学生信息,总共需录入10位学生信息')
name = input('请输入学生姓名:')
age = input('请输入学生年龄:')
address = input('请输入学生地址:')
# 创建学生对象并添加到列表中
student = Student(name, age, address)
students_list.append(student)
# 输出学生信息
print(f'学生{i}的信息录入完成,信息为:【学生姓名:{student.name},年龄:{student.age},地址:{student.address}】')
# 打印所有学生信息
print('\n所有学生信息如下:')
for i, student in enumerate(students_list, start=1):
print(f'学生{i}:【学生姓名:{student.name},年龄:{student.age},地址:{student.address}】')
魔术方法
# __init__构造方法,是Python类内置的方法之一,可用于创建类对象的时候设置初始化行为
# 有各种内置方法,称之为魔术方法
# __str__字符串方法
class Student:
def __init__(self, name, age):
self.name = name # 学生姓名
self.age = age # 学生年龄
stu = Student('周杰伦', 31)
print(stu)
print(str(stu))
# 得到内存地址,通过str魔术方法来控制一下类对象转变字符串的行为
"""
<__main__.Student object at 0x0000022E11411FD0>
<__main__.Student object at 0x0000022E11411FD0>
"""
# __str__魔术方法转换字符串
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# __str__魔术方法
def __str__(self):
return f'Student类对象,name:{self.name}, age:{self.age}'
stu = Student('周杰伦', 31)
print(stu)
print(str(stu))
"""
Student类对象,name:周杰伦, age:31
Student类对象,name:周杰伦, age:31
"""
# __lt__小于符号的比较方法,小于和大于符号的比较
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# __str__魔术方法
def __lt__(self, other):
return self.age < other.age
stu1 = Student('周杰伦', 31)
stu2 = Student('林俊杰', 36)
print(stu1 < stu2)
print(stu1 > stu2)
"""
True
False
"""
# __le__小于等于符号的比较魔术方法
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# __le__魔术方法
def __le__(self, other):
return self.age <= other.age
stu1 = Student('周杰伦', 31)
stu2 = Student('林俊杰', 36)
print(stu1 <= stu2)
print(stu1 >= stu2)
"""
True
False
"""
# __eq__比较运算符实现方法,当前类对象和其他类对象(other)进行比较
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# __le__魔术方法
def __eq__(self, other):
return self.age == other.age
stu1 = Student('周杰伦', 36)
stu2 = Student('林俊杰', 36)
print(stu1 == stu2)
"""
True
"""
封装
# 面向对象,基于模板(类)去创建实体(对象),使用对象完成功能开发。
# 面向对象包含3大主要特性:
# 1、封装,将现实世界的属性和行为封装到类中描述为成员属性和成员方法,从而完成程序对现实世界的描述
# 2、继承
# 3、多态
# 定义私有成员:(类中描述属性和方法的时候是不公开对使用者开放的)
# 私有成员变量(方法):变量(方法)名以__开头(2个下划线)即可完成私有成员的设置
"""
演示面向对象封装思想中私有成员的使用
"""
# 定义一个类,内含私有成员变量和私有成员方法
class Phone:
__current_voltage = None # 当前手机运行电源
def __keep_single_core(self):
print('让CPU以单核模式运行')
phone = Phone()
phone.__keep_single_core() # 私有成员方法无法使用
"""
AttributeError: 'Phone' object has no attribute '__keep_single_core'.
"""
class Phone:
__current_voltage = None # 当前手机运行电源
def __keep_single_core(self):
print('让CPU以单核模式运行')
phone = Phone()
print(phone.__current_voltage) # 私有成员变量无法使用
"""
AttributeError: 'Phone' object has no attribute '__current_voltage'.
"""
# 内部的其他成员可以使用
# 类对象无法访问私有成员,但类中的其他成员可以访问私有成员
class Phone:
__current_voltage = 1 # 当前手机运行电源
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通话,并已设置为单核运行进行省电')
phone = Phone()
phone.call_by_5g()
"""
5g通话已开启
"""
# __current_voltage = 0.5时,可以访问__keep_single_core私有成员方法
"""
让CPU以单核模式运行
电量不足,无法使用5g通话,并已设置为单核运行进行省电
"""
封装案例
# 设计一个手机类,内部包含:
# ·私有成员变量:_is_5g_enable,类型bool,True表示开启5g,False表示关闭5g
# ·私有成员方法:__check_5g(),会判断私有成员_is_5g_enable的值
# ·若为True,打印输出:5g开启
# ·若为False,打印输出:5g关闭,使用4g网络
#
# 公开成员方法:call_by_5g(),调用它会执行
# ·调用私有成员方法:__check_5g(),判断5g网络状态
# ·打印输出:正在通话中
#
# 运行结果:
# 5g关闭,使用4g网络
# 正在通话中
# 设计一个类,用来描述手机
class Phone:
# 提供私有成员变量
__is_5g_enable = False
def __check_5g(self): # 提供私有成员方法:__check_5g
if self.__is_5g_enable:
print('5g开启')
else:
print('5g关闭,使用4g网络')
def call_by_5g(self): # 提供公有成员方法:call_by_5g
self.__check_5g()
print('正在通话中')
phone = Phone()
phone.call_by_5g()
"""
5g关闭,使用4g网络
正在通话中
"""
class Phone:
# 提供私有成员变量
__is_5g_enable = True
def __check_5g(self):
if self.__is_5g_enable:
print('5g开启')
else:
print('5g关闭,使用4g网络')
def call_by_5g(self):
self.__check_5g()
print('正在通话中')
phone = Phone()
phone.call_by_5g()
"""
5g开启
正在通话中
"""
继承的基础语法
"""
演示面向对象:继承的基础语法
"""
# 演示单继承
class Phone:
IMEI = None # 序列号
producer = 'HM' # 厂商
def call_by_4g(self):
print('4g通话')
class Phone2022(Phone):
face_id = '10001' # 新增面部识别方法
def call_by_5g(self):
print('2022年新功能,5g通话')
# 新旧都能调用
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
"""
HM
4g通话
2022年新功能,5g通话
"""
# 多继承
# class 类名(父类1, 父类2,……,父类N):
# 类内容体
class Phone:
IMEI = None # 序列号
producer = 'HM' # 厂商
def call_by_4g(self):
print('4g通话')
class NFCReader:
nfc_type = '第五代'
producer = 'HM'
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()
"""
4g通话
NFC读卡
NFC写卡
红外遥控开启
"""
# 两个producer厂商不同,谁先继承,谁的优先级最高(最高)
class Phone:
IMEI = None # 序列号
producer = 'ITCAST' # 厂商
def call_by_4g(self):
print('4g通话')
class NFCReader:
nfc_type = '第五代'
producer = 'HM'
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)
"""
4g通话
NFC读卡
NFC写卡
红外遥控开启
ITCAST
"""
复写父类成员和调用父类成员
# 复写:子类继承父类的成员属性和成员方法后,如果对其“不满意”,
# 那么可以进行复写。即:在子类中重新定义同名的属性或方法即可。
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)
"""
开启CPU单核模式省电
使用5g网络进行通话
关闭CPU单核模式
ITHEIMA
"""
# 调用父类同名成员
# 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
# 如果需要使用被复写的父类的成员,需要特殊的调用方式:
# 方式1:
# 调用父类成员
# 使用成员变量:父类名.成员变量
# 使用成员方法:父类名.成员方法(self)
# 方式2
# 使用super()调用父类成员
# 使用成员变量:super().成员变量
# 使用成员方法:super().成员方法()
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单核模式省电')
# 方式1
print(f'父类的厂商是:{Phone.producer}')
Phone.call_by_5g(self)
# 方式2
print(f'父类的厂商是:{super().producer}')
super().call_by_5g()
print('关闭CPU单核模式')
phone = MyPhone()
phone.call_by_5g()
print(phone.producer)
"""
开启CPU单核模式省电
父类的厂商是:ITCAST
使用5g网络进行通话
关闭CPU单核模式
ITHEIMA
"""
变量的类型注解
# 类型注解的语法,并不影响程序的运行,告诉pycharm变量是什么类型,方便编程
# 基础语法: 变量:类型
# 基础数据类型注解
import json
import random
var_1: int = 10
var_2: float = 3.1415
var_3: bool = True
var_4: str = 'HEIMA'
# 类对象类型注解
class Student:
pass
stu: Student = Student() # stu对象是Student这个类的类型
# 基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {'heima': 666}
my_str: str = 'heima'
# 容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[str, int, bool] = ('heima', 666, True)
my_set: set[int] = {1, 2, 3}
my_dict: dict[str, int] = {'heima': 666}
# 注意:
# 元组类型设置类型详细注解,需要将每一个元素都标记出来
# 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
# 在注释中进行类型注解语法:
# type:类型
class Student:
pass
# var_1 = random.randint(1, 10) # type: int
# var_2 = json.loads('{'name': 'zhangsan'}') # type: dict[str, str]
def func():
return 10
var_3 = func() # type: Student
# 类型注解的限制
var_4: int = 'heima'
var_5: str = 123
# 上述标记错了但不会影响程序运行,只是协助代码提示和备注
函数和方法的类型注解
# 函数(方法)的类型注解-形参注解
def func(data):
data.app # 想用append但没任何提示(pycharm不知道data是什么类型)
func()
# 在编写函数(方法),使用形参data的时候,工具没有任何提示在调用函数(方法),
# 传入参数的时候,工具无法提示参数类型这些都是因为,我们在定义函数(方法)的时候,
# 没有给形参进行注解
# 函数和方法的形参类型注解语法:
# def 函数方法名(形参名:类型,形参名:类型……):
# pass
# 对形参进行类型注解
def add(x: int, y: int):
return x + y
add(1, 2)
# 函数和方法的返回值也可以添加类型注解语法:
# def 函数方法名(形参名:类型,形参名:类型……)-> 返回值类型:
# pass
def func(data: list) -> list: # 第一个list是形参data的类型注解,第二个list是返回值的类型注解
return data
func(func(1)) # 不影响程序运行
Union联合类型注解
# 演示Union联合类型注解(
# 使用Union类型,必须先导包
from typing import Union
my_list: list[Union[int, str]] = [1, 2, 'heima']
def func(data: Union[int, str]) -> Union[int, str]:
pass
func() # pycharm会提醒int或者str
多态
# 多态,指的是:多种状态,同一个行为,使用不同的对象获得不同的状态。
# 定义函数(方法),通过类型注解声明需要父类对象,实际传入子类对象进行工作
# 从而获得不同的工作状态
"""
演示面向对象的多态特性以及抽象类(接口)的使用
"""
# 演示多态,使用2个子类对象来调用函数
class Animal:
def speak(self):
pass # 父类Animal的speak方法,是空实现
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)
"""
汪汪汪
喵喵喵
"""
# 父类Animal的speak方法,是空实现,这种设计的含义是:
# 父类用来确定有哪些方法
# 具体的方法实现,由子类自行决定
# 这种写法叫抽象类(也称为接口)
# 抽象类:含有抽象方法的类称之为抽象类
# 抽象方法:方法体是空实现的(pass)称之为抽象方法,比如:
# class Animal:
# def speak(self):
# pass
# 用途,国家定义了空调的国家标准,有不同的功能(抽象类)
# 不同公司实现了不同的功能(子类实现)
# 演示抽象类
# 抽象类,通常作为顶层设计,具体方法实现由后续子类完成,也是对子类的软性约束,
# 要求子类必须复写(实现)父类的一些方法
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空调对象
ac.cool_wind() # 具体工作
# 具体的实现
midea_ac = Midea_AC()
gree_ac = GREE_AC()
make_cool(midea_ac)
make_cool(gree_ac)
"""
美的空调制冷
格力空调制冷
"""
数据处理案例main.py
# 使用面向对象思想完成数据读取和处理
# 基于面向对象思想重新认知第三方库使用(PyEcharts)
# 需求分析:读取数据->封装数据对象->计算数据对象->pyecharts绘图
# 对应需求:设计(FileReader类)->设计(数据封装类)->对对象进行逻辑计算->以面向对象思想重新认识pyecharts
"""
面向对象,数据分析案例,主业务逻辑代码
实现步骤:
1. 设计一个类,可以完成数据的封装(data_define.py)
2. 设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能(两个文件不同读取方法csv和json,逻辑不一样)
3. 读取文件,生产数据对象data_define.py、file_define.py
4. 进行数据需求的逻辑计算(计算每一天的销售额)
5. 通过PyEcharts进行图形绘制
"""
from file_define import FileReader, TextFileReader, JsonFileReader
from data_define import Record
from pyecharts.charts import Bar
from pyecharts.options import *
from pyecharts.globals import ThemeType
text_file_reader = TextFileReader("D:/2011年1月销售数据.txt")
json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.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
# 开始进行数据计算
# {"2011-01-01": 1534, "2011-01-02": 300, "2011-01-03": 650}
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 = 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")
数据处理案例data_define.py
"""
数据定义的类
"""
class Record:
# 构造方法
def __init__(self, date, order_id, money, province):
"""
构造方法中使用成员变量
:param date:
:param order_id:
:param money:
:param province:
"""
self.date = date # 订单日期
self.order_id = order_id # 订单ID
self.money = money # 订单金额
self.province = province # 销售省份
# 使用魔术方法将file_define中的内存地址转化为字符串
def __str__(self):
return f"{self.date}, {self.order_id}, {self.money}, {self.province}"
数据处理案例file_define.py
"""
和文件相关的类定义
"""
import json
from 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() # 消除读取到的每一行数据中的\n
data_list = line.split(",")
record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])
record_list.append(record) # 返回成list
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"], int(data_dict["money"]), data_dict["province"])
record_list.append(record)
f.close()
return record_list
if __name__ == '__main__':
text_file_reader = TextFileReader("D:/2011年1月销售数据.txt")
json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.txt")
list1 = text_file_reader.read_data()
list2 = json_file_reader.read_data()
# for l in list1:
# print(l) # 打印内容得到内存地址,要在data_define.py中使用魔术方法__str__转化
#
# for l in list2:
# print(l)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3415226167@qq.com