面向对象
提示:本文根据b站黑马python课整理
链接指引 => 2022新版黑马程序员python教程
一、初识对象
使用对象组织数据
在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的。
在程序中
设计表格
,我们称之为:设计类(class)
class Student: name = None
在程序中
打印生产表格
,我们称之为:创建对象
# 基于类创建对象 stu1 = Student() stu2 = Student()
在程序中
填写表格
,我们称之为:对象属性赋值
stu1.name = '111' stu2.name = '111'
二、成员方法
2.1 类的定义和使用
类的使用语法:
- class是关键字,表示要定义类了
- 类的属性,即定义在类中的变量(成员变量)
- 类的行为,即定义在类中的函数(成员方法)
class 类名称:
类的属性
类的行为
创建类对象的语法:
对象 = 类名称()
2.2 成员变量和成员方法
类中定义的属性(变量),我们称之为:成员变量
类中定义的行为(函数),我们称之为:成员方法
2.2.1 成员方法的定义语法
def 方法名(self, 行参1, ..., 行参n):
方法体
可以看到,在方法定义的参数列表中,有一个:self
关键字
self关键字是成员方法定义的时候,必须填写
的。
- 它用来表示类对象自身的意思
- 当我们使用类对象调用方法的是,self会自动被python传入
在方法内部,想要访问类的成员变量,必须使用self
def say_hi(self):
print(f"hi大家好,我是{self.name}")
注意事项:self关键字,尽管在参数列表中,但是传参的时候可以忽略它。
三、类和对象
基于类创建对象的语法: 对象名 = 类名称()
四、构造方法
Python类可以使用:__init__()
方法,称之为构造方法。
可以实现:
- 在创建类对象(构造类)的时候,
会自动执行。
- 在创建类对象(构造类)的时候,
将传入参数自动传递给__init__方法使用。
在构造方法内定义成员变量,需要使用self
关键字
class Student:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
stu = Student('天天', 30, '1111')
案例:
学生信息录入
# 学生信息录入
class Student:
id = None
name = None
age = None
address = None
def insert (self, id, name, age, address):
self.id = id
self.name = name
self.age = age
self.address = address
print(f'学生{id}信息录入完成,信息为:【学生姓名:{name},年龄:{age},地址:{address}】')
idx = 10
for i in range(0, idx):
print(f'当前录入第{i+1}位学生信息,总共需录入10位学生信息')
name = input('请输入学生姓名:')
age = input('请输入学生年龄:')
address = input('请输入学生地址:')
stu = Student()
stu.insert(i+1, name, age, address)
if i+1 == 10:
print('10位学生信息录入完毕!')
五、其它内置方法(魔术方法)
上文学习的__init__ 构造方法,是Python类内置的方法之一。
这些内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法
方法 | 功能 |
---|---|
__init__ | 构造方法,可用于创建类对象的时候设置初始化行为 |
__str__ | 用于实现类对象转字符串的行为 |
__lt__ | 用于2个类对象进行小于或大于比较 |
__le__ | 用于2个类对象进行小于等于或大于等于比较 |
__eq__ | 用于2个类对象进行相等比较 |
5.1 __str__
字符串方法
内存地址没有多大作用,我们可以通过__str__
方法,控制类转换为字符串的行为。
- 方法名:
__str__
- 返回值:字符串
- 内容:自行定义
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}"
5.2 __lt__
小于符号比较方法(__gt__
大于符号比较方法)
直接对2个对象进行比较是不可以的,但是在类中实现__lt__
方法,即可同时完成:小于符号 和 大于符号 2种比较比较大于符号的魔术方法是:__gt__
不过,实现了__lt__
,__gt__
就没必要实现了
- 方法名:
__lt__
- 传入参数:other,另一个类对象
- 返回值:True 或 False
- 内容:自行定义
5.3 __le__
小于等于比较符号方法
魔术方法:__le__
可用于:<=、>=两种比较运算符上。
- 方法名:
__le__
- 传入参数:
other
,另一个类对象- 返回值:
True
或False
- 内容:自行定义
>=
符号实现的魔术方法是:__ge__
不过,实现了__le__
,__ge__
就没必要实现了
5.4 __eq__
,比较运算符实现方法
不实现 __eq__
方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果
。
实现了__eq__
方法,就可以按照自己的想法来决定2个对象是否相等了。
- 方法名:
__eq__
- 传入参数:
other
,另一个类对象- 返回值:
True
或False
- 内容:自行定义
六、封装
面向对象的三大特性
- 封装
- 继承
- 多态
封装表示的是,将现实世界事物的:
- 属性
- 行为
封装到类中,描述为:
- 成员变量
- 成员方法
6.1 私有成员
既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持。
类中提供了私有成员的形式来支持。
- 私有成员变量
- 私有成员方法
定义私有成员的方式非常简单,只需要:
- 私有成员变量:变量名以__开头(2个下划线)
- 私有成员方法:方法名以__开头(2个下划线)
即可完成私有成员的设置
class Phone:
__is_5g_enable = False # 私有成员变量
def __check_5g(self): # 私有成员方法
print('5g开启')
练习:
设计带有私有成员的手机
# 设计带有私有成员的手机
import random
class Phone:
__is_5g_enable = False
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()
phone.call_by_5g()
a = random.randint(1,2)
七、继承
- 什么是继承?
继承就是一个类,继承另外一个类的成员变量和成员方法 语法:
- 子类构建的类对象,可以
- 有自己的成员变量和成员方法
- 使用父类的成员变量和成员方法
- 单继承和多继承
单继承:一个类继承另一个类
多继承:一个类继承多个类,按照顺序从左向右依次继承
多继承中,如果父类有同名方法或属性,先继承的优先级高于后继承 pass关键字
的作用是什么pass
是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
7.1 继承的基础语法
7.1.1 单继承
class 类名(父类名):
类内容体
继承分为:单继承和多继承
使用如图语法,可以完成类的单继承。
继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有
7.1.2 多继承
一个类,可以继承多个父
class 类名(父类1,父类2,...., 父类n):
类内容体
多继承注意事项:
多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。
即:先继承的保留,后继承的被覆盖
7.2 复写和使用父类成员
7.2.1 复写
复写:子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。
即:在子类中重新定义同名的属性或方法即可。
class FileReader:
def read_file(self):
"""读取文件的数据,读到的每一条数据都转换为Record对象,将他们封装到list"""
pass
# 文本文件的读取
class TextFileRead(FileReader):
def __init__(self, path):
self.path = path # 定义文件路径
# 复写父类的方法
def read_file(self):
print('11111')
7.2.2 调用父类同名成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类的成员,需要特殊的调用方式:
方式1:
- 调用父类成员
- 使用成员变量:
父类名.成员变量
- 使用成员方法:
父类名.成员方法(self)
方式2:
- 使用
super()
调用父类成员 - 使用成员变量:
super().成员变量
- 使用成员方法:
super().成员方法()
只能在子类内调用父类的同名成员。
子类的类对象直接调用会调用子类复写的成员
八、类型注解
8.1 变量的类型注解
- 为变量设置类型注解
基础语法:变量: 类型
注意:
元组类型设置类型详细注解,需要将每一个元素都标记出来
字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
- 除了使用 变量: 类型, 这种语法做注解外,也可以在注释中进行类型注解。
语法:# type: 类型
8.2 函数(方法)的类型注解
函数和方法的形参类型注解语法:
def 函数方法名(形参名:类型,形参名:类型,.....):
pass
同时,函数(方法)的返回值也是可以添加类型注解的。
语法如下:
def 函数方法名(形参名:类型,形参名:类型,.....) -> 返回值类型:
pass
def read_file(x: int, y: int) -> list[int]:
pass
8.3 Union类型
Union的使用方式:
- 导包:from typing import Union
- 使用:Union[类型, ......, 类型]
九、多态
多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
9.1 抽象类(接口)
这种设计的含义是:
- 父类用来确定有哪些方法
- 具体的方法实现,由子类自行决定
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法
抽象类的作用
- 多用于做顶层设计(设计标准),以便子类做具体实现。
- 也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法
- 并配合多态使用,获得不同的工作状态。
十、案例
数据分析案例
main.py
"""
面向对象,数据案例分析
"""
from pyecharts.charts import Line, Bar
from pyecharts.options import *
from pyecharts.globals import ThemeType
from file_define import TextFileRead, JsonFileReader, FileReader
from data_define import Record
text_file_reader = TextFileRead('./data/2011年1月销售数据.txt')
json_file_reader = JsonFileReader('./data/2011年2月销售数据JSON.txt')
jan_data: list[Record] = text_file_reader.read_file()
feb_data: list[Record] = json_file_reader.read_file()
# 将两个月份的数据合并为一个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
# 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('每日销售额echarts.html')
file_defined.py
"""
和文件相关的类定义
"""
import json
from data_define import Record
class FileReader:
def read_file(self) -> list[Record]:
"""读取文件的数据,读到的每一条数据都转换为Record对象,将他们封装到list"""
pass
# 文本文件的读取
class TextFileRead(FileReader):
def __init__(self, path):
self.path = path # 定义文件路径
# 复写父类的方法
def read_file(self) -> list[Record]:
f = open(self.path, 'r', encoding="UTF-8")
record_list: list[Record] = []
for line in f.readlines():
line = line.strip() # 消除空格和换行
data_list = line.split(',')
record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])
record_list.append(record)
# print(record_list)
f.close()
return record_list
# Json文件的读取
class JsonFileReader(FileReader):
def __init__(self, path):
self.path = path # 定义文件路径
def read_file(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 = TextFileRead('./data/2011年1月销售数据.txt')
text_json = JsonFileReader('./data/2011年2月销售数据JSON.txt')
list1 = text_file.read_file()
list2 = text_json.read_file()
for l in list1:
print(l)
for l in list2:
print(l)
data_defined.py
"""
数据定义的类
"""
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}"
总结
以上就是python向对象,之后会持续更新,欢迎大家点赞关注呀~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。