一、初识对象
使用对象组织数据。在程序中可以做到和生活中一样,设计表格、生产表格、填写表格的组织形式的。
1.在程序中设计表格:--设计类
class Studen:
name = None #记录学生姓名
2.在程序中打印生产表格:--创建对象
# 基于类创建对象
stu_1 = Student()
stu_2 = Student()
3. 在程序中填写表格:--对象属性赋值
stu_1.name = "张三" # 为对象赋予name属性
stu_2.name = "张四"
"""
演示类的创建
"""
# 1.设计一个学生类 :类比生活中设计一张记录学生信息的登记表
class Student:
name = None
gender = None
nationality = None
native_place = None
age = None
# 2.创建一个对象(类比生活中打印一张登记表)
stu_1 = Student()
stu_2 = Student()
# 3.对象属性进行赋值(类比生活中:填写表单)
stu_1.name = "张三"
stu_1.gender = '男'
stu_1.nationality = "中国"
stu_1.native_place = "山东省"
stu_1.age = "23"
# 4.获取对象中记录的信息
print(stu_1.name)
print(stu_1.gender)
print(stu_1.nationality)
print(stu_1.native_place)
print(stu_1.age)
二、成员方法
1、类的定义和使用语法:
-
class是关键字,表示要定义类了
-
类的属性,即定义在类中的变量(成员变量)
-
类的行为,即定义在类中的函数(成员方法)
语法:
class 类名称:
类的属性
类的行为
创建类对象的语法: 对象 = 类名称()
2、成员变量和成员方法的使用:
什么是类的行为(方法)?
可以看出 类中可以:
-
定义属性用来记录数据
-
定义函数用来记录行为
其中:
-
类中定义的属性(变量)称作-- 成员变量
-
类中定义的行为(函数)称作-- 成员方法
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
可以看到,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的。
· 它用来表示类对象自身的意思
· 当我们使用类对象调用方法的是,self会自动被python传入
·
在方法内部,想要访问类的成员变量,必须使用self
3、self关键字
self --尽管在参数列表中,但是传参的时候可以忽略它
"""
演示面向对象类中的成员方法定义和使用
"""
# 定义一个带有成员方法的类
class Student:
name = None
def say_hi(self):
print(f"大家好,我是{self.name}")
def say_hi2(self,msg):
print(f"大家好,我是{self.name},{msg}")
stu_1 = Student()
stu_1.name = "李四"
stu_1.say_hi2("哎哟不错呀")
stu_2 = Student()
stu_2.name = "李wy"
stu_2.say_hi()
三、类和对象
现实世界的事物也有属性和行为,类也有属性和行为;
实用程序中的类,可以完美的描述现实世界的事物。那么为什么要创建对象才能使用呢?
类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作
。这种思想就称之为:
面向对象编程
使用类和对象描述现实事物
在程序中通过类来描述;
基于类创建对象
这就是面向对象编程:
--设计类,基于类创建对象,由对象做具体的工作。
四、构造方法
1、属性(成员变量)的赋值
2、
构造方法:
Python类可以使用__init__()方法,称之为构造方法
可以实现:--在创建类对象(构造类的时候)
-
会 自动执行
-
将参数自动传递给__init__方法使用
3、构造方法注意事项
-
重要的事情说三遍,构造方法名称:__init__ __init__ __init__ , 千万不要忘记init前后都有2个下划线
-
构造方法也是成员方法,不要忘记在参数列表中提供:self
-
在构造方法内定义成员变量,需要使用self关键字
这是因为:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。
4、构造方法案例:
"""
设计一个类,记录学生的:
姓名、年龄、地址,这3类信息
通过for循环,配合input输入语句,并使用构造方法,完成学生信息的键盘录入
输入完成后,使用print语句,完成信息的输出
"""
class Student:
name = None
age = None
addres = None
def __init__(self,name,age,addres):
self.name = name
self.age = age
self.addres = addres
for x in range(1,10):
name_in = input("请输入学生姓名:")
age_in = input("请输入学生年龄:")
address_in = input("请输入学生地址:")
stu = Student(name_in,age_in,address_in)
print(f"当前录入第{x}位学生信息,总共需要录入10位学生信息")
print(f"学生{x}信息录入完成,信息为:【学生姓名:{stu.name},年龄:{stu.age},地址:{stu.addres}】")
print("所有学生的信息录入完毕")
五、其他内置方法 --魔术方法
目录
1、__str__ 字符串方法
2、__lt__ 小于符号比较方法
直接对2个对象进行比较是不可以的,但是在类中实现__lt__方法,即可同时完成:
小于符号 和 大于符号 2种比较
方法名:__lt__
传入参数:other,另一个类对象
返回值:True 或 False
内容:自行定义
3、__le__ 小于等于比较符号方法
魔术方法:__le__可用于:<=、>=两种比较运算符上。
4、__eq__,比较运算符实现方法
-
不实现__eq__方法, 对象之间可以比较,但是是比较 内存地址,也即是:不同对象==比较一定是False结果。
-
实现了__eq__方法,就可以按照自己的想法来决定2个对象是否相等了。
"""
演示Python内置的各类魔术方法
"""
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
# __str__ 控制类对象转变为字符串
def __str__(self):
return f"{self.name},{self.age}"
# __lt__ 小于符号比较方法--实现小于符号 和 大于符号 2种比较
def __lt__(self, other):
return self.age < other.age
# __le__ 小于等于比较符号方法--实现<=、>=两种比较运算符
def __le__(self, other):
return self.age <= other.age
# __eq__ 比较运算符实现方法
def __eq__(self, other):
return self.age == other.age
stu1 = Student("自制力",32)
stu2 = Student("养成",21)
print(stu1) # 输出:自制力,32
print(str(stu1)) # 输出:自制力,32
print(stu1.age > stu2.age) #输出True
print(stu1.age < stu2.age) #输出False
print(stu1.age <= stu2.age) #输出False
print(stu1.age >= stu2.age) #输出True
print(stu1.age == stu2.age) #输出False
六、面向对象编程特性
面向对象编程
是 许多编程语言都支持的一种编程思想;简单理解是:基于模板(类)去创建实体(对象),使用对象完成功能开发
面向对象的三大特性:
-
封装
-
继承
-
多态
1、封装
· 对用户隐藏的属性和行为:
现实世界中的事物,有属性和行为。但是不代表所有的属性和行为都是开放给用户使用的
· 私有成员
类中提供了私有成员的形式来支持不公开的属性和行为
-
私有成员变量
-
私有成员方法
定义私有成员的方式:
-
私有成员变量:变量名以__开头(2个下划线)
-
私有成员方法:方法名以__开头(2个下划线) 即可完成私有成员的设置
使用私有成员:
私有成员无法被类对象使用,但是可以被其他成员的成员使用。简而言之,私有的可以被内部使用,但是不能被外部创建的类对象使用。
"""
演示面向对象封装思想中私有成员的使用
"""
class Phone:
__cunrent_voltage = 0.3 # 当前手机运行电压 私有
def __keep_single_core(self): # 私有方法
print("让CPU以单核模式运行")
def call_by_5g(self):
if self.__cunrent_voltage >= 1:
print("5g通话已开启")
else:
self.__keep_single_core()
print("电量不足,无法使用5G通话,并已设置为单核模式。")
phone = Phone()
phone.call_by_5g()
#输出:
让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网络状态 打印输出:正在通话中
"""
设计一个手机类,内部包含:
私有成员变量:__is_5g_enable,类型bool,True表示开启5g,False表示关闭5g
私有成员方法:__check_5g(),会判断私有成员__is_5g_enable的值
若为True,打印输出:5g开启
若为False,打印输出:5g关闭,使用4g网络
公开成员方法:call_by_5g(),调用它会执行
调用私有成员方法:__check_5g(),判断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()
通过这个案例,可以概括:私有成员有什么意义? --可以直接去定义不直接对用户开放的属性和行为。
2、继承:
继承的概念引出
对于phone更新迭代,设计师肯定会选择基于老款的设计图,修修改改。
即新的设计图本质上继承了老设计图思路再进行修改
如何基于老的类来进行升级修改? --使用继承来实现
继承分为
单继承和多继承
继承表示从父类那里继承(复制)成员变量和成员方法
不含私有
class 类名(父类名):
类内容体
· 单继承:
"""
演示面向对象--继承--单继承基础语法
"""
# 父类
class Phone:
IMEI = None # 序列号
producer = "SP" #厂商
def call_by_4g(self):
print("4g通话")
# 单继承
class Phone2022(Phone):
faceID = "10001" #面部识别
def call_by_5g(self):
print("2022年新功能:5G通话")
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
输出:
SP
4g通话
2022年新功能:5G通话
· 多继承
Python之间也支持多继承,即一个类,可以继承多个父类
多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。即:先继承的保留,后继承的被覆盖
"""
演示面向对象--多继承
注意:对于父类中同名的成员(成员属性和成员方法)访问时,按照左边的先来 谁先继承谁的优先级高
"""
class Phone:
IMEI = None # 序列号
producer = "SP" #厂商
__store = 512
def call_by_4g(self):
print("4g通话")
class NFCReader:
NFC_type = "第五代"
producer = "SPbear"
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 # 作用是不产生语法错误 pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
phone = myPhone()
phone.call_by_4g()
phone.read_card()
phone.write_card()
phone.control()
print(phone.producer)
输出:
4g通话
NFC读卡
NFC写卡
红外遥控开启了
SP
· 复写和使用父类方法:
(1)复写:子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。即:在子类中重新定义同名的属性或方法。
(2)调用父类同名成员
一旦复写父类成员,那么对象调用成员的时候,就会调用复写后的新成员;如果需要使用被复写的父类的成员,需要特殊的调用方式:
只能在
子类内调用父类的同名成员
。子类的类对象直接调用会调用子类复写的成员
"""
面向对象继承--复写使用父类成员
"""
# 父类
class Phone:
IMEI = "20221210"
producer = "SP"
def call_by_5g(self):
print("5g通话模式")
# 定义子类 复写父类
class myPhone(Phone):
producer = "SPplus"
def call_by_5g(self):
print("开启CPU单核模式,保持通话省电")
# # 方式1 通过父类名调用父类里面的成员
# print(f"父类的厂商:{Phone.producer}")
# Phone.call_by_5g(self) # 调用父类的成员方法 括号内一定要加self
# 方式2 利用super
print(f"父类的厂商:{super().producer}")
super().call_by_5g()
print("关闭CPU单核模式,确保性能")
phone = myPhone()
phone.call_by_5g()
print(phone.producer,phone.IMEI)
输出:
开启CPU单核模式,保持通话省电
父类的厂商:SP
5g通话模式
关闭CPU单核模式,确保性能
SPplus 20221210
3、类型注解
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。
主要功能:
-
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
-
帮助开发者自身对变量进行类型注释
支持:
-
变量的类型注解
-
函数(方法)形参列表和返回值的类型注解-
·
类型注解的语法
(1)为变量设置类型注解 --基础语法:
变量:类型
(2)对注释进行类型注解 语法:type: 类型
(3)类型注解的限制
类型注解主要功能在于:
· 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
· 帮助开发者自身对变量进行类型注释(备注)
并不会真正的对类型做验证和判断。
也就是,类型注解仅仅是提示性的,不是决定性的 不会报错的哦。
(4)函数和方法的类型注解 形参注解/返回值注解
形参注解语法:
返回值注解语法:
(5)Union联合类型注解
使用Union[类型, ......, 类型] 可以定义
联合类型注解
Union联合类型注解,在
变量注解、函数(方法)形参和返回值注解中,均可使用。
4、多态
· 多态:多种状态,即完成某个行为时,使用不用的对象 会得到不同的状态
同样的行为(函数),传入不同的对象,得到不同的结果
· 抽象类(接口)
提出标准后,不同的厂家各自实现标准的要求
抽象类的作用:
可以用于做顶层的设计( 设计标准),以便子类做具体实现
也是对子类的一种软性约束要求子类必须复写(实现)父类的一些方法,配合多态使用获得不同的工作状态。
七、综合案例 --数据分析
案例需求:某公司,有2份数据文件,现需要对其进行分析处理,计算每日的销售额并以柱状图表的形式进行展示。
需求分析
1、
使用面向对象思想完成数据读取和处理
· 1月份数据是普通文本,使用逗号分割数据记录,从前到后分别是(日期,订单id,销售额,销售省份)
· 2月份数据是JSON数据,同样包含(日期,订单id,销售额,销售省份)
2、
基于面向对象思想重新认知第三方库使用(PyEcharts)
实现步骤:
1、设计一个类可以完成数据的封装
2、设计一个抽象类 定义文件读取的相关功能,并使用子类实现具体功能
3、读取文件生产数据对象
4、进行数据需求的逻辑计算(计算每一天的销售额)
5、通过pyecharts进行图形绘制
代码和数据