一 初识对象
1.生活中数据的组织
2.程序中数据的组织
3.使用对象组织数据
类的属性:
二 成员方法
1.类的定义和使用
2.成员变量和成员方法
类外面是函数,类里面是方法。
3.成员方法的定义语法
self 只是写在这里,传参的时候可以当作不存在。
4.注意
类名首字母一般大写。
没有 student.name = "xxx" 就是默认的。
三 类和对象
1.现实世界的事务和类
现实世界中的事物可以分为两个特征:
2.类和对象
3.使用类和对象描述现实事物
在程序中通过类来描述。
4.基于类创建对象
面向对象编程就是让对象干活。
# 类名大写
class Clock:
id = None
price = None
def ring(self):
# python 内置的模块,让电脑发出声音
import winsound
# 2000是频率,3000是响铃时间
winsound.Beep(2000,3000)
# 构建干活的对象
clock1 = Clock()
clock1.id = "003032"
clock1.price = 19.99
print(f"闹钟ID:{clock1.id},价格:{clock1.price}")
clock1.ring()
clock2 = Clock()
clock2.id = "003033"
clock2.price = 199.99
print(f"闹钟ID:{clock2.id},价格:{clock2.price}")
clock2.ring()
四 构造方法
1.属性(成员变量)的赋值
通过传参的方式,把成员变量的值传进去。
2.构造方法
构造函数 __init__
在创建类对象时自动执行,用于初始化对象的属性和设置初始状态。
当 stu
对象被创建时,Python 会自动调用 Student 类的 __init__
方法。这个方法接受两个参数 age
和 tel
,并将它们赋值给对象的属性 self.age
和 self.tel
。
上面三行如果写了就是对成员变量的赋值,如果省略不写就是对成员变量进行声明并且赋值。
3.注意
不管什么方法,只要是类里面的方法,都必须带上 self 。
只要在类的方法中访问类成员变量都要通过 self 。
4.课堂练习
class Student :
def __init__(self,name,age,adress):
self.name = name
self.age = age
self.adress = name
for num in range(1,11):
a = input("请输入学生姓名:")
b = input("请输入学生年龄: ")
c = input("请输入学生地址: ")
stu = Student(a, b, c)
print(f"学生{num}信息录入完成,信息为:【学生姓名:{stu.name},年龄:{stu.age},地址:{stu.adress}")
print(f"当前录入第{num + 1}位学生信息,总共需录入10位学生信息")
五 其它内置方法
1.魔术方法
_str_字符串方法
这个魔术方法就是返回字符串,当我们需要把这个类的对象变成字符串,它就通过魔术方法的形式去获得要变成什么样的字符串,如果不写就输出内存地址,写了就输出你要的形式。
为什么不打印 return 的内容:
print()
语句只显示 print()
内部的内容,而 return
语句返回的内容需要被显式地打印。
要同时打印 return
的内容,可以将 return
的结果传递给 print()
。
_It_小于符号比较方法
报错是因为当前类在定义的时候没有支持比较的功能,所以无法比较。
_Ie_小于等于比较符号方法
_eq_比较运算符实现方法
六 封装
1.面向对象的三大特性
2.封装
3.对用户隐藏的属性和行为
4.私有成员
5.使用私有成员
如何定义私有成员:
上网前要检查手机的电压是否正常,开了程序需要程序调度,内存管理。
私有的东西不是给用户使用的,是给自己的功能使用的
6.课堂练习
用户不用管怎么检查5g,只管打电话就行了,所以把检查改成私有的。
class Phone :
__is_5g_enable = False
def __check_5g(self):
if self.__is_5g_enable == True:
print("5g开启")
else:
print("5g关闭,使用4g网络")
def call_by_5g(self):
self.__check_5g()
print("正在通话中")
phone = Phone()
phone.call_by_5g()
七 继承
1.为什么有继承
2.单继承
3.多继承
4.注意
生父,养父,义父。
写类的时候 class ...(...): 冒号里面不想写别的,可以用 pass ,表示空,功能只是补全语法。
5.复写
覆盖。
6.调用父类同名成员
变成只添加第1和3行的 print ,再直接调用父类的 print 。
多个父类指名点比较好。
八 类型注解
1.为什么要类型注解
是增加代码可读性的,加不加对程序没任何影响,只是方便人看。
2.什么是类型注解
3.类型注解的语法
因为 python 定义变量时不声明,才有了这些注解。
类 Student ,构建对象 stu 。
自己定义的时候可以看出来,但是代码一多起来自己就混乱了,目的是让 pycharm 在后面的使用过程中提示这个东西是什么类型的。
字典的注解第一个表示 key ,第二个表示 value 。
使用 random 要导包, 按 alt + 回车键可以自动搜索并导包。选 import this name 。
4.类型注解的限制
5.函数(方法)的类型注解
形参注解
ctrl + p 弹出提示
返回值注解
也是建议性的,不是决定性的。
6.Union 类型
什么是Union 类型
里面的数据不规则,有混合的类型。表示要么...类型要么...类型。
表示键是 str ,值可能是 str 也可能是 int 。
U要大写。
使用 Union 类型要先导包。
Union 的使用方式
九 多态
1.什么是多态
右边代码:函数接收了一个animal的对象,注解了类型是Animal,调用了animal对象的speak。传入的是子类对象。父类有speak方法,子类继承了父类。这些dog,cat是对象,不是变量。
再定义了两个子类的对象,没有传入父类对象,而是在调用这个函数的时候把dog和cat传进去,然后输出汪汪汪和喵喵喵。
传入不同的对象得到不同的输出,传入dog是汪汪汪,传入cat是喵喵喵。
要传入 animal 对象。
构建两个子类对象来调用这个函数。有两个子类的具体对象。
然后调用make_noise,要求传入Animal类型,但是不传入父类对象,而是传入两个具体的子类对象。
make_noise是函数,括号内是形参,填入对象就是调用speak方法了。
同样的行为 make_noise 使用不同的对象,获得不同的运行状态。
2.抽象类(接口)
什么是抽象类(接口)
抽象方法:方法体是空实现的。Animal类包含了抽象方法,所以叫抽象类。
抽象类(接口)的作用
AC 这个类并不是拿来直接使用的,不会获取 AC 的具体对象,作用是顶层设计。
真正工作的是 AC 的子类。第2列进行了复写才可以正常工作,因为父类什么也没写
抽象类是顶层代码,就是规划下面如何如何设计的,这个类没有什么功能,就是一个集合体,功能都由其子类去实现。
有了具体的子类,就可以完成多种状态的工作了,构建具体的子类对象,函数内传入子类对象去工作,同一个制冷行为,传入不同的对象,就得到不同的状态。
父类规范内容,以pass结束,等待子类实现具体功能。
十 综合案例
需求:每日销售额
只要将日期和对应的日期金额求和即可。
步骤1:
步骤2:文件读取
使用抽象类的原因:有两份数据文件,第一份里面是标准的文本,通过逗号分隔数据。
第2份数据是json。
文件不同,读取文件的具体实现逻辑也不一样,所以构建抽象类。
先在最顶级设计好读取文件应该有哪些基础功能,但是不实现,然后通过具体的子类(文本读取子类)( json 读取子类)来实现具体数据的具体读取方法。
抽象类的定义就是为多态的使用做准备,有不同的数据,但是要完成同样的行为而制定的统一规则,定义抽象类以后,通过子类来实现相同行为的不同内容。
如果不加这个 __str__ 方法,就会输出数据的内存地址。
因为如果一个类没有定义这两个方法,print()
函数将会输出对象的内存地址,而不是对象的实际内容。read_data()方法返回的是一个 record_list 列表,这个列表是通过每一次Record对象追加得到的,所以如果直接循环打印就会打印出内存地址。
加上__str__ :
输出内存地址的原因是 Record
类的 __str__
方法没有被调用。
只能用 for 循环才能调用到
Record
类的__str__
方法吗
步骤3:数据计算
from file_define import FileReader,TextFileReader,JsonFileReader
from data_define import Record
# 读取数据 read_data
text_file_reader = TextFileReader("D:/2011年1月销售数据.txt")
json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.txt")
one_data = text_file_reader.read_data() # type:list[Record]
# list 类型,放的是 Record 对象
two_data = json_file_reader.read_data() # type:list[Record]
# 把两个月份的数据合并成一个 list
all_data = one_data + two_data # type:list[Record]
# 数据计算 数据有日期,每一条都有销售额
# 把1号所有的销售额都取到,然后累加求个和
# 初始:{“2011-01-01”:0} ,然后 for 循环列表,把符合的和初始0相加
data_dict = {}
# 列表 all_data 里面每一个元素都是一个对象,date,order_id,money,province
for i in all_data : # record 是 Record 对象
if i.date in data_dict.keys():
# 当前日期已经有记录了,只要和老数据做累加即可
# 取出老数据
data_dict[i.date] += i.money
else:
# 还没有这个日期被记录
data_dict[i.date] = i.money
# 最后字典 data_dict 里面就记录了每一天的销售额
print(data_dict)
步骤4:可视化
from step3 import *
from pyecharts.charts import Bar
# 柱状图
from pyecharts.options import *
# 选项
from pyecharts.globals import ThemeType
# 主题类型,图表颜色
# 构建类对象 通过 Bar 这个类得到类对象 bar
bar = Bar()
# 添加 x 轴数据:日期
# 需要传入 list
bar.add_xaxis(list(data_dict.keys()))
# 添加y轴
bar.add_yaxis("销售额",list(data_dict.values()))
# 给图表设置标题
bar.set_global_opts(
title_opts=TitleOpts(title="每日销售额")
)
bar.render("每日销售额柱状图.html")
让 y 轴不要显示数字:
修改颜色:
(已解决)为什么只能写from step3 import * 才对。