Python面向对象
文章目录
一、初识面向对象
在Python中,一切皆为对象,对象是类的实例。类是一种抽象数据类型,它定义了对象的属性(成员变量)和方法(成员函数)。通过类可以创建多个具有相似属性和行为的对象,以下是Python面向对象编程的基本概念:
名称 | 概念 |
---|---|
类(Class) | 类是对象的模板,它定义了对象的属性和方法。可以通过class关键字来定义类。 |
对象(Object) | 对象是类的实例,可以根据类创建多个对象。每个对象都有自己的状态(属性)和行为(方法)。 |
属性(Attribute) | 类中定义的变量称为属性,用于存储对象的状态。 |
方法(Method) | 类中定义的函数称为方法,用于描述对象的行为。 |
继承(Inheritance) | 子类可以继承父类的属性和方法,并且可以重写父类的方法或者添加新的方法。 |
举一个抽象的例子,在生活中我们如何记录某个班级的学生信息?较好的方式是设计学生填写信息的表格、打印表格、学生进行填写。在程序中我们也可以已填写表格的形式组织数据,如下例子:
# 1、定义类 (设计学生填写的表格)
class studentInfo:
studentName = None
studentGender = None
studentAge = None
studentPhone = None
studentWechat = None
# 2、创建对象 (打印表格)
student_1 = studentInfo
# 3、对象属性赋值 (学生填写表格)
student_1.studentName = "zhangsan"
student_1.studentGender = "男"
student_1.studentAge = "21"
student_1.studentPhone = "66666699"
student_1.studentWechat = "QIN2783862"
二、成员方法
1、定义类和成员方法的语法
创建类的语法:
class 类名称:
类的属性 # 类的属性,即定义在类中的变量(成员变量)
类的行为 # 类的行为,即定义在类中的函数(成员方法)
注意:函数是写在类外面的,定义在类里面的,我们称作为方法!
成员方法定义语法:
在类中定义成员方法和定义函数基本一致,但仍有细微区别。
def 方法名(self, 形参1, 形参2, ....)
方法体
可以看到,在方法定义的参数列表中,有一个self
关键字
-
self关键字是定义成员方法的时候,必须填写的。
-
self关键字用来表示类对象自身的意思。
-
当使用类对象调用方法的时候,self会自动被python传入。
-
在方法内部,访问类的成员变量,必须加上self。
2、定义成员方法注意事项及案例
注意事项:
- 定义成员方法时,要传入self关键字,表示类本身。
- 成员方法中,使用类中的变量,要使用self关键字。
示例代码:
class studentInfo:
studentName = None
def studentPrint(self, msg): # 定义成员方法时,要传入self关键字,表示类本身
print(f"大家好,我是{self.studentName} ,{msg}") # 使用类中的变量,要使用self关键字
stu_1 = studentInfo()
stu_1.studentName = "周杰伦"
stu_1.studentPrint("哎呦不错哦")
输出内容:
大家好,我是周杰伦 ,哎呦不错哦
三、魔术方法
1、什么是魔术方法及常见的魔术方法
在Python的面向对象编程中,有一些特殊的方法,通常被称为"魔术方法"或"特殊方法"。这些方法以双下划线开头和结尾(例如__init__
)来命名,它们提供了一种在类中定义特定行为的方式。以下是一些常用的魔术方法:
魔术方法 | 说明 |
---|---|
__init__ | 构造方法,在创建对象时候自动执行,用于初始化对象 |
__del__ | 析构方法,用于释放对象 |
__str__ | 返回对象的字符串表示 |
__lt__ | 小于符号比较方法 |
__le__ | 小于等于比较方法 |
__eq__ | 等于比较方法 |
__repr__ | 返回对象的可打印表示,通常用于调试 |
__len__ | 返回对象的长度 |
__getitem__ | 获取指定索引的值 |
__setitem__ | 设置指定索引的值 |
__delitem__ | 删除指定索引的值 |
__iter__ | 返回迭代器对象,用于迭代 |
__next__ | 返回迭代器的下一个值 |
__contains__ | 判断对象是否包含指定元素 |
__add__ | 实现加法操作 |
__sub__ | 实现减法操作 |
__mul__ | 实现乘法操作 |
__call__ | 使对象可以像函数一样被调用 |
__enter__ | 进入上下文时的操作 |
__exit__ | 离开上下文时的操作 |
2、__init__构造方法代码示例
——init——
方法会在创建对象的时候,自动执行。
代码示例:
class studentInfo:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
print(f"调用__init_方法: 姓名{self.name}, 年龄{self.age}, 性别{self.gender}")
stu = studentInfo("zhangsan", "22", "man") # 创建对象自动执行_init_方法
输出内容:
调用__init_方法: 姓名zhangsan, 年龄22, 性别man
3、__srt_字符串方法代码示例
__str__
方法,用于定义对象的字符串表示形式。当我们使用内置的 str()
函数或打印对象时,就会调用该方法。
代码示例:
class studentInfo:
def __init__(self, name, age):
self.name = name
self.age = age
print(f"__init__方法:{self.name}, {self.age}")
def __str__(self):
return f"__str__方法:{self.name}, {self.age}"
stu = studentInfo("zhangsan", "22")
print(stu)
print(str(stu))
输出内容:
__init__方法:zhangsan, 22
__str__方法:zhangsan, 22
__str__方法:zhangsan, 22
注意:__str__
方法应该返回一个字符串,如果返回其他类型的值,可能会引发异常。
4、__lt__小于符号比较方法
__lt__
方法,用于定义对象之间的小于比较运算。当我们使用小于符号 <
比较两个对象时,就会调用这个方法。
代码示例:
class studentInfo:
def __init__(self, name, age):
self.name = name
self.age = int(age)
def __lt__(self, other):
return self.age < other.age
stu_1 = studentInfo("zhangsan", 25)
stu_2 = studentInfo("lisi", 23)
print(stu_1 > stu_2)
输出内容:
True
注意:在 __lt__
方法中,应该使用小于符号 <
来定义比较。
5、__le__小于等于符号比较方法
和__lt__
方法用法一致,但__le__
多了一个=
判断
代码示例:
class studentInfo:
def __init__(self, name, age):
self.name = name
self.age = int(age)
def __le__(self, other):
return self.age <= other.age
stu_1 = studentInfo("zhangsan", 25)
stu_2 = studentInfo("lisi", 25)
print(stu_1 <= stu_2)
输出内容:
True
6、__eq__等于符号比较方法
代码示例:
class studentInfo:
def __init__(self, name, age):
self.name = name
self.age = int(age)
def __eq__(self, other):
return self.age == other.age
stu_1 = studentInfo("zhangsan", 30)
stu_2 = studentInfo("lisi", 30)
print(stu_1 == stu_2)
输出内容:
True
四、封装
1、封装概念
封装是一种面向对象编程的概念,它指的是将数据和对数据的操作封装在一个单独的对象中,以实现数据的隐藏和保护。通过封装,可以控制对象的访问权限,并提供公共接口来操作对象的属性和方法。
2、私有成员
类中提供了私有成员的形式来支持,隐藏对象的不公开属性和行为,定义私有成员方式非常简单,如下:
- 私有成员变量:变量名以__开头(2个下划线)
- 私有成员方法:方法名以__开头(2个下划线)
私有成员的限制:
- 类对象无法访问私有成员。
- 类中的其他成员可以访问私有成员。
示例代码:
class phone:
__current_voltage = 0.5 # 当前手机电压(私有变量)
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(f"当前电压为{self.__current_voltage}不能以5G模式运行")
user = phone()
user.call_by_5g()
输出内容:
CPU以单核模式运行
当前电压为0.5不能以5G模式运行
3、封装案例
需求:
设计一个手机类,内部包含:
- 私有成员变量:
__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 = 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("正在通话中...")
user = phone()
user.call_by_5g()
输出内容:
5G开启
正在通话中...
五、继承
通过继承,子类可以继承父类的属性和方法,并且还可以在子类中添加新的属性和方法或者修改父类的属性和方法。
1、单继承与多继承基础语法
基本语法:
class 类(父类1, 父类2, ...)
类内容体
单继承与多继承解释:
- 单继承:一个类继承一个父类。
- 多继承:一个类继承多个类,按照顺序从左到右依次继承。
- 多继承中,如果父类有同名方法或属性,先继承的优先级高于后继承。
单继承示例代码:
class phone2021:
modelId = "2021-12-03"
def call_phone_3g(self):
print("phone2021: 3G通话已开启...")
class phone2022(phone2021): # 继承单个phone20211203类
modelId = "2022-12-03"
def call_phone_4g(self):
print("phone2022: 4G通话已开启...")
user = phone2022()
user.call_phone_3g()
user.call_phone_4g()
输出内容:
phone2021: 3G通话已开启...
phone2022: 4G通话已开启...
多继承示例代码:
# 定义网络类
class network:
def network_5G(self):
print("已启动5G网络...")
def network_4G(self):
print("已启动4G网络...")
# 定义NFC读卡器类
class nfc:
def nfc_read(self):
print("已启动NFC读取权限....")
def nfc_write(self):
print("已启动NFC写入权限...")
class phone(network, nfc): # 多继承
pass
user = phone()
user.network_5G()
user.network_4G()
user.nfc_write()
user.nfc_read()
输出内容:
已启动5G网络...
已启动4G网络...
已启动NFC写入权限...
已启动NFC读取权限....
2、复写
子类继承父类后,对父类的属性和成员方法 “不满意”,那么可以进行复写,就是修改父类中的属性和成员方法。
即:在子类中重新定义同名的属性可方法即可。
示例代码:
class phone:
id = '20221203'
def call_by_5g(self):
print("启用5G通话功能....")
class phone2023(phone):
id = '20231203' # 复写父类变量
def call_by_5g(self): # 复写父类成员方法
print("启动单核CPU模式.....")
print("启用5G通话功能....")
print("通话结束,关闭单核CPU模式.....")
user = phone2023()
user.call_by_5g()
print(f'当前ID: {user.id}')
输出内容:
启动单核CPU模式.....
启用5G通话功能....
通话结束,关闭单核CPU模式.....
当前ID: 20231203
3、使用父类同名成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员,如果需要使用被复写的父类的成员,需要特殊的调用方式如下:
- 方式一,调用父类成员:父类名.(成员变量|成员方法)
- 方式二,使用super()调用父类成员:super().(成员变量|成员方法)
示例代码:
class phone:
id = '20221203'
def call_by_5g(self):
print("启用5G通话功能....")
class phone2023(phone):
id = '20231203'
def call_by_5g(self):
print("启动单核CPU模式.....")
"""
第一种方式:
phone.call_by_5g(self)
print(f"父类ID: {phone.id}")
"""
# 第二种方式:
super().call_by_5g()
print(f"父类ID: {super().id}")
print("通话结束,关闭单核CPU模式.....")
user = phone2023()
user.call_by_5g()
print(f'当前ID: {user.id}')
输出内容:
启动单核CPU模式.....
启用5G通话功能....
父类ID: 20221203
通话结束,关闭单核CPU模式.....
当前ID: 20231203
六、类型注解
类型注解是指在代码中标注变量、函数参数和返回值的数据类型信息,以便在静态分析工具或IDE中进行类型检查。类型注解并不会改变 Python 解释器的行为,它们只是一种形式化的标记,用于说明代码中变量和函数的预期类型。
1、基础数据的类型注解
基本注解语法:
名称: 类型 = 值
注释类型语法:
# type: 类型
基本注解-示例代码:
# 变量类型注解
var1: int = 2793863
var2: float = 1.84
var3: bool = True
var4: str = "QIN"
# 容器类型注解(基本类型注解)
t1_list: list = [1, 2, 3]
t1_tuple: tuple = (1, 2, 3)
t1_set: set = {1, 2, 3}
t1_dict: dict = {"QIN": 2793863}
t1_str: str = "QIN2793863"
# 容器类型注解(详细类型注解)
t2_list: list[int] = [1, 2, 3]
t2_tuple: tuple[int, str, bool] = (1, "QIN", True)
t2_set: set[int] = {1, 2, 3}
t2_dict: dict[str, int] = {"QIN": 2793863}
# 类对象注解
class t1_class:
pass
t1: t1_class = t1_class()
注意:
- 元组类型设置详细注解,需要将每一个元素都标记出来。
- 字典类型设置详细注解,需要2个类型,第一个是key,第二个是value。
注释类型注解-示例代码:
t1_var = 2793863 # type: int
t1_list = [1, 2, 3] # type: list
t1_dict = {"QIN": 666} # type: dict
t1_tuple = (1, 2, 3) # type: tuple
class t1_class:
pass
t1 = t1_class() # type: t1_class
2、函数(方法)的类型注解
形参注解基本语法:
def 函数名(变量1: 注解类型, ...):
函数返回值注解基本语法:
def 函数名(变量1: 注解类型, ...) -> 函数返回值注解类型:
形参注解-示例代码:
def sumNum(x: int, y: int): # 形参注解
return x + y
result = sumNum(100, 200)
函数返回值注解-示例代码:
def sumNum(x: int, y: int) -> int: # 函数返回值注解
return x + y
result = sumNum(100, 200)
print(result)
3、Union联合类型注解
类型注解的 Union
用于指定一个变量可以是多种类型中的一种,这在处理函数参数、返回值或其他变量时非常有用,因为有时候变量可能具有多种不同的类型。
基本语法:
from typing import Union
Union[类型1, 类型2, ...]
示例代码:
from typing import Union
# 注解t1_list列表是int类型或者str类型
t1_list: list[Union[int, str]] = [1, 2, "QIN", "TEST"]
# 注解func函数形参是int类型或者str类型
# 注解func函数返回值是int类型或者str类型
def func(data: Union[int, str]) -> Union[int, str]:
pass
七、多态
1、多态基本概念
多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
示例代码:
# 定义父类(动物)
class Animal:
def speak(self):
pass
# 定义子类(狗)
class Dog(Animal):
def speak(self):
print("汪汪汪~")
# 定义子类(猫)
class Cat(Animal):
def speak(self):
print("喵喵喵~")
def make_noise(animal: Animal):
animal.speak()
dog = Dog()
cat = Cat()
make_noise(dog)
make_noise(cat)
输出内容:
汪汪汪~
喵喵喵~
2、抽象类
抽象类就好比定了一个标准,包含一些抽象方法,要求子类必须满足实现,这种设计含义是:
- 父类用来确定设置哪些标准
- 具体的实现方法,由子类自行确定
抽象类的作用:
- 多用于顶层设计(设计标准),以便子类做具体实现。
- 也就是子类的一种软性约束,要求子类必须复写(实现)父类的一些方法。
示例代码:
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.cool_wind()
midea_ac = Midea_AC()
gree_ac = GREE_AC()
make_cool(midea_ac)
make_cool(gree_ac)
输出内容:
美的空调,制热~
格力空调,制热~
3、多态和抽象类的区别
在Python中,多态和抽象类是面向对象编程的两个重要概念,它们有一些相似之处,但也存在一些区别。
-
多态:简单来说,多态就是同一个方法名可以被不同类型的对象调用,并且这些对象可以具有不同的实现方式。也就是说,在不同的情况下,同一个函数名可以实现不同的功能。例如,同一个
speak
方法在狗和猫这两个不同的类中会有不同的实现方式。在 Python 中,多态通常通过继承和方法重写来实现。 -
抽象类:抽象类是不能直接实例化,只能作为其他类的子类使用。它定义了一组通用的方法或属性,但这些方法或属性不会被具体实现。相反,需要在继承自该抽象类的具体子类中进行实现。这样,就可以保证所有子类都有相同的接口,并且可以避免代码重复。在 Python 中,抽象类通常通过
abc
模块来实现。
下面是多态和抽象类的一些区别:
- 定义形式:
- 多态:通过继承和方法重写实现多态,子类重写父类的方法来改变方法的行为。
- 抽象类:通过定义抽象方法来实现抽象类,抽象方法在抽象类中只有函数声明,没有具体实现。
- 实例化:
- 多态:多态的关键在于父类引用变量指向子类对象,通过父类引用变量调用方法时,实际执行的是子类对象的方法。
- 抽象类:抽象类不能被实例化,只能作为其他类的基类来使用,子类必须实现抽象类中的所有抽象方法才能实例化。
- 使用场景:
- 多态:多态可以方便地处理不同类型的对象,提高代码的灵活性和可扩展性。
- 抽象类:抽象类主要用于定义一组相关的类的接口和共同行为,并作为其他具体类的基类使用。
总结来说,多态是一种对象调用同一个方法产生不同行为的机制,而抽象类是一种将具有相似行为的类的接口进行抽象的机制。多态通常通过继承和方法重写来实现,而抽象类则通过定义抽象方法来实现。
八、综合案例
通过面向对象思想实现数据可视化,示例代码如下:
import json
from pyecharts.charts import Bar
from pyecharts.options import *
from pyecharts.globals import ThemeType
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}"
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()
data_list = line.split(",")
record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])
record_list.append(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(date=data_dict["date"], order_id=data_dict["order_id"], money=int(data_dict["money"]),
province=data_dict["province"])
record_list.append(record)
f.close()
return record_list
# 读取数据
text_file_reader = TextFileReader("file/2011年1月销售数据.txt")
json_file_reader = JsonFileReader("file/2011年2月销售数据JSON.txt")
jan_data: list[Record] = text_file_reader.read_data()
feb_data: list[Record] = json_file_reader.read_data()
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
# 可视化开发
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")
最终生成柱状图如下:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!