文章目录
大家好,我是技术界的小萌新,今天要和大家分享一些干货。在阅读之前请先点赞👍,给我一点鼓励吧!这对我来说很重要 (*^▽^*)
一、初识对象
1、什么是面向对象?
面向对象(Object-Oriented, OOP)是一种编程范式,它使用“对象”来设计软件,这些对象包含数据(通常称为属性或字段)和代码(通常称为方法或函数),以模拟现实世界实体的属性和行为。
一句话总结: 面向对象是一种编程方法,通过创建包含数据和行为的对象来模拟现实世界,提高代码的组织性、重用性和灵活性。
在 Python 中,想要使用 类
,必须先 创建对象
。
2、成员方法
1) 类的定义和使用
class 类名称: # class 关键字,表示定义了一个类,类首字符大写为标准。
类的属性 # 类的属性(Attribute):即定义在类中的变量(成员变量)
类的行为 # 类的行为:即定义在类中的函数(成员方法)
类的使用:
- 创建类的对象:语法: 对象 = 类名称()
- 使用对象:object.name = value
2) 成员方法的定义
def 方法名(self, 形参1, 形参2, 形参3 ···)
方法体
print(self.name)
# 在成员方法(类的行为)中调用成员变量(类的属性)时,必须加上 self,不然会导入外界变量 name。
# 类的属性(成员变量)需要与外界变量作出区别。
self 关键字:定义成员方法时,必须填写的。
- 它用来表示成员变量自身(即导入的对象 (成员))的意思。
- 当我们使用类对象调用方法时,
self
会自动被 Python 传入。 - 在方法内部,想要访问类的成员变量,必须使用 self。
3、类和方法
目标: 掌握使用类描述现实世界事物的思想。
现实世界中的事物和类: 现实世界的事物由什么组成? --> 行为(事) + 属性(物) 组成可以形成 类 (class)
即类也可以包含 行为 和 属性,所以用类来描述现实世界中的事物是十分合适的。
面向对象编程
面向对象编程思想:
为什么非要创建对象才可以使用类?因为类只是一种程序内的 ”设计图纸“,需要基于图纸生产实体(对象),才能正常工作,这种思路,称之为:“面向对象编程"
。
面向对象编程核心:
重要:
- 设计类
- 基于类创建对象
- 由对象做具体的工作
4、属性(成员变量)的赋值
给类的属性赋值是一项繁琐的工作。但可以有更便捷的方式,就是使用 构造方法。
构造(创建类对象的)方法:
Python 类可以使用:__init__()
方法,称之为构造方法。定义了构造方法,创建对象就必须传参。
可以实现:使用构造方法对成员变量进行赋值。
- 在创建类对象(构造类)的时候,会自动执行。
- 在创建类对象(构造类)的时候,将传入参数自动传递给__init__ 方法使用。
# 构造方法使用示例:
class Student:
name = None # 可以省略
age = None # 可以省略
tel = None # 可以省略,由构造方法实现 类属性(成员变量)的 定义、传入赋值。
def __init__(self,name,age,tel): # 创建类对象时,允许向类传递实参,实参被定义 __init__ 函数内的形参
self.name = name # 接收了,并赋给了 类的属性,由此 类的属性 再次定义,上述声明可省略。
self.age = age
self.tel = tel
5、其他类内置方法
魔法方法: 即类的内置方法,如已经学习过的 __init__ 构造方法。
1) str 字符串方法
当打印对象时会输出对象的内存地址,无用。
可以通过 __str__
方法,控制打印时类对象转换为字符串的行为。
定义:
def __str__(self): # 定义/重写 __str__ 内置魔法方法
return f"string" # print 打印时,自动调用 __str__ 内置方法,输出返回值。
示例:
# 构造方法使用示例:
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return f"Studen 类对象,name: {self.name}, age: {self.age}"
if __name__ == '__main__':
student = Student("张三", 18)
print(student)
打印:
Studen 类对象,name: 张三, age: 18, tel: 12345678901
进程已结束,退出代码为 0
2) lt 小于符号比较方法
2 个类对象不支持直接进行比较大小,可以通过 __lt__
同时完成:小于符号、大于符号 2 种的比较。
定义:
def __lt__(self, other): # 定义类的固定属性比较标准,other 表示另一个类的对象。
return self.age < other.age # 默认比较 < 小于符号,不要变 > 大于符号,判断大小的逻辑会反转。
返回值:True or False
注意:
这里(经尝试)发现调用 < 或 > 时,尖头所对为 self。
就比如 stu1 < stu2,那么 stu1 就会作为 __lt__ 定义中的 self,而 stu2 作为 other。
示例:
class Student:
def __init__(self,name,age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
if __name__ == '__main__':
s1 = Student('张三', 10)
s2 = Student('李四', 20)
print(s1 < s2)
打印:
True
3) le 小于等于符号比较方法
同上,用于类对象之间的 小于等于 比较。
定义:
def __le__(self, other): # 定义类的固定属性比较标准,other 表示另一个类的对象。
return self.age <= other.age # 默认比较 <= 小于符号,不要变 >= 大于符号,判断大小的逻辑会反转。
4) eq 等于符号比较方法
print(stu1 == stu2)
默认比较的是 2 个对象的 内存地址
,肯定输出 False
所以 __eq__
魔法方法 用于使得 等于符号 可以正常用来比较 2 个对象之间的属性。其他 同 __lt__ 方法。
定义:
def __eq__(self, other):
return self.age == other.age
二、Python 面向对象编程三大特性
1、封装
Python 面向对象编程 三大特性:
➢ 封装、继承、多态。
封装:表示将现实世界中的事物 属性、行为封装到类中,描述为 成员变量、成员方法。
私有成员:非公开的属性及行为。(此类属性(成员变量)会影响全局,但是外部却无法影响类中的它,将用户与系统使用的属性隔离了开来。)
- 分为 私有成员变量、私有成员方法。
- [访问限制] 私有方法无法被类对象调用
- [访问限制] 私有变量也无法被类对象赋值,也无法被获取值。
定义方法:
__成员变量
、__成员方法
。 加上__
两个下划线即可。
私有成员的实际意义: 在类中提供仅内部使用的属性和方法,而不对外开放(类对象无法使用)。
2、继承
新版本的子类通过继承可以引入父类,此时新类只需要关注开发新版本类的方法功能,而无需写入父类内容,方便程序功能快速的更新迭代。
1) 单继承
一个子类只继承单个父类的属性方法。
# 单继承 语法
class 子类名(父类名):
类内容体
2) 多继承
一个子类继承多个父类的属性方法。按照顺序从左往后继承。
# 多继承 语法
class 子类名(父类1, 父类2, 父类3 ···)
类内容体
pass
- pass 关键字:当只需继承各个父类功能,不写其他代码时使用。补全语法,防止语法报错,标注此处为空。
警告:
- 如果多个父类具有同名属性,则按照继承顺序,
自左向右,优先级降低
,先继承的保留,后继承的被覆盖。
3) 复写
子类继承父类后,对父类成员进行修改的一种方法。
使用方法: 在子类中重新定义与父类同名的成员属性、方法即可 复写父类成员属性、方法
。
调用父类同名成员:一旦复写父类成员,在子类中调用父类成员时,就会调用成复写后的子类成员。如果需要调用父类成员,则需要特殊的调用方法。
方式 1:
父类名.成员变量
、父类名.成员方法(self)
# 此时需要标明 self,传入 父类自己。方式 2:使用 super() 超类 调用父类成员
- 调用成员变量:
super().成员变量
- 调用成员方法:
super().成员方法()
class Phone:
name = "cwy"
def call_5g(self):
print("5g通信")
class Myphone(Phone):
name = "cmj"
def call_5g(self):
print(Phone.name) # 方式一调用父类变量
Phone.call_5g(self) # 方式一调用父类方法
print(super().name) # 方式二调用父类变量
super().call_5g() # 方式二调用父类方法
phone=Myphone()
print(phone.name)
phone.call_5g()
3、多态
多态:指的是 多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
同样的类行为(函数),传入不同的对象,得到不同的状态。
继承、多态多联用,继承功能保证使用子类实现了父类设计的方法,然后不同的对象就与父类设计的方法一致,通过多态的函数保证了用子类传入函数来实现不同对象的同一父类行为的不同状态输出。
传入 不同子类对象 使用父类定义的功能 --> 不同的子类们完成同一行为 --> 获得不同状态的输出(不同对象在同一父类行为上不同的结果)
多态使用场景:
- 与继承联用。
- 使用在 抽象类(接口) [策略与机制的分离] 抽象类(接口)特征: 父类方法使用 pass 空实现,来做决策。
抽象类: 含有抽象方法的类称之为抽象类,为类的 “顶层设计”,制定标准。
抽象方法: 类的方法体是空实现 (pass) 特征的 ,称之为抽象方法,子类必须对此抽象方法进行重写。
抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现。
抽象类配合多态可实现:
- 抽象的父类设计 (设计标准)
- 具体的子类实现 (实现标准)
抽象类的作用:多用于做顶层设计(设计标准),以便子类做具体实现,也是对子类的一种软性约束,要求子类必须复写(实现)父类的抽象方法,并配合多态使用,获得不同的工作状态。
4、综合理解
以下是二维对象数组列表示例,每一个列表元素都是一个对象:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# def __str__(self):
# return f"Studen 类对象,name: {self.name}, age: {self.age}"
list_ins = [["张三", 18], ["李四", 19], ["王五", 20]]
tmp = []
if __name__ == '__main__':
for i in list_ins:
stu = Student(i[0], i[1])
tmp.append(stu) # 对象的累加器,累加的每一行对象的内存地址都被存储成元素。
print(tmp) # 打印 二维数组列表。
for i in tmp: # 遍历 二维数组列表的每一个对象。
print(i.name, i.age) # 打印 二维数组列表每一个对象的类属性值。
打印:
[<__main__.Student object at 0x0000015EFABFD9A0>]
[<__main__.Student object at 0x0000015EFABFD9A0>, <__main__.Student object at 0x0000015EFABFDA30>]
[<__main__.Student object at 0x0000015EFABFD9A0>, <__main__.Student object at 0x0000015EFABFDA30>, <__main__.Student object at 0x0000015EFABFDA60>]
张三 18
李四 19
王五 20
四、类型注解
为什么需要类型注解? 为了帮助 Pycharm 等其他 IDE 进行自动提示、补全。
因为: Pycharm 确定了这个对象是什么类型。
类型注解: 在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。
注释:
Python 在 3.5 版本的时候引入了类型注解,以方便静态类型检查工具,IDE 等第三方工具。
主要功能:
帮助第三方 IDE 工具(如 PyCharm)对代码进行类型推断,协助做代码提示。帮助开发者自身对变量进行类型注释。
支持:
变量的类型注解。(少用)函数(方法)形参列表和返回值的类型注解。(常用)
1、变量类型注解
类型注解语法如下所示:
① 基础语法: 变量: 数据类型、变量: 类、变量: 容器类型[数据类型]
② 注释注解: # type: 类型
注意:
元组 tuple类型 设置类型详细注解,需要将每一个元素都标记出来
字典 dict 类型 设置类型详细注解,需要 2 个类型,第一个是 key 第二个是 value
2、函数(方法)的类型注解
形参注解: def ins(name: str, age: int):
返回值注解:def ins(name: str, age: int) -> int:
标注返回值为 int,None 说明无返回值。
3、Union 联合类型注解
如数据容器的混合数据类型,Union 可以注解多个不同的数据类型。
需要导入包:from typing import Union
Union[str,int···]
: 表示数据容器内的数据类型要么是 str
、要么是 int
基础语法:
my_list: list[Union[str, int, list, bool]] = ["ins", 6, [1, 2, 3], True]
my_dict: dict[Union[str, int], Union[int, str, list]] = {"str": 1, 1: [1, "ss", [1, 2, 3]]}
def ins(name: str, age: int) -> Union[str, int]
pass
# 函数体为空即可,防止报错
from typing import Union
# 字典调用时,不像 ansible 用 . 表示嵌套字典的层级关系,一律用 [ ] 来索引嵌套列表与其中的列表元素。
my_dict: dict[Union[str, int], Union[int, str, list]] = {"str": 1, 1: [1, "ss", [1, 2, 3]]}
print(my_dict[1][2][2]) # 提示内容:my_dict: dict[str | int, int | str | list] = {"str": 1, 1: [1, "ss", [1, 2, 3]]}
打印:
3
文章到这里就结束了,希望我的分享能为你的技术之旅增添一抹亮色。如果你喜欢这篇文章,请点赞收藏支持我,给予我前行的动力!🚀