在学习js的时候,学到面向对象的时候也是一脸懵逼,在学到python的这个面向对象的时候虽然接受的比当时快了一点,但是学到最后还是很蛋疼啊
下面是面向对象的概述(当然也是将大佬的直接拿来用了):
OOP思想:
接触到任意一个任务,首先想到的是任务这个世界的构成,是由模型构成的
几个名词:
OO:面向对象
OOA:面向对象的分析
OOD:面向对象的设计
OOI:xxx的实现
OOP:xxx的编程
OOA->OOD->OOI: 面向对象的实现过程
类和对象的概念
类:抽象名词,代表一个集合,共性的事物
对象:具象的事物,单个个体
类跟对象的关系:
一个具象,代表一类事物的某一个个体
一个是抽象,代表的是一大类事物
类中的内容,应该具有两个内容:
表明事物的特征,叫做属性(变量)
表明事物功能或动作, 称为成员方法(函数)
类和对象的成员分析:
1、类和对象都可以存储成员,成员可以归类所有,也可以归对象所有
2、类存储成员时使用的是与类关联的一个对象
3、独享存储成员是是存储在当前对象中
4、对象访问一个成员时,如果对象中没有该成员,尝试访问类中的同名成员, 如果对象中有此成员,一定使用对象中的成员
5、创建对象的时候,类中的成员不会放入对象当中,而是得到一个空对象,没有成员
6、通过对象对类中成员重新赋值或者通过对象添加成员时,对应成员会保存在对象中,而不会修改类成员
关于self:
1、self在对象的方法中表示当前对象本身,如果通过对象调用一个方法,那么该对象会自动传入到当前方法 的第一个参数中
2、self并不是关键字,只是一个用于接受对象的普通参数,理论上可以用任何一个普通变量名代替
3、方法中有self形参的方法成为非绑定类的方法,可以通过对象访问, 没有self的是绑定类的方法, 只能通过类访问
4、使用类访问绑定类的方法时, 如果类方法中需要访问当前类的成员,可以通过 __class__成员名来访问
类的基本实现:
1、类的命名:
类名使用大驼峰规则,避开跟系统命名相似的
2、声明语法:
class 类名:
成员属性= 值
def 成员方法名(self):
代码块。。。
3、实例化类:
变量 = 类名()
4、访问类的成员属性和成员方法
变量.成员属性
变量.成员方法
5、查看对象或类的所有成员
对象(类).__dict__
6、声明了一个类:
class A(): --->声明类
name = 'weiY'
def func(self):
self.name = 'wei'
print(self.name)
def func2():
print(__class__.name)
class B():
name = 'Y'
a = A() --->实例化
A.func2() ---> 没有self的是绑定类的方法, 只能通过类访问
a.func() ---> wei
A.func(a) --->wei
A.func(A) --->weiY
A.func(B) --->Y
以上的调用就只是想说明:在调用带有self的类成员方法的时候,如果调用时没有入参那么self就是对象,如果有那就是入参的那个对象。
面向对象的三大特性:
1、封装
封装有三个级别:
公开成员:对成员没有任何限制,任何地方都可以访问
受保护成员:在成员名前加一个下划线(_成员名),在类或子类中可以访问,在外部不可以
私有成员:在成员名前加两个下划线(__成员名),在当前类或对象中才能访问。但是真的想要访问私有成员还是可以的,方法就是:_类名__私有成员名
2、继承:继承就是一个类可以获得另外一个类中的成员属性和成员方法
a.作用: 减少代码,增加代码的复用功能, 同时可以设置类与类直接的关系
b.继承与被继承的概念:
被继承的类叫父类,也叫基类,也叫超类
用于继承的类,叫子类,也叫派生类
继承与被继承一定存在一个 is-a 关系
c.继承的语法:(B类继承了A类,就是在声明的括号里将父类带进去)
class A():
pass
class B(A): ==》B类继承A类,A是B的父类
pass
d.继承的特征
1、所有的类都继承自object类,即所有的类都是object类的子类
2、子类一旦继承父类,则可以使用父类中除私有成员外的所有内容
3、子类继承父类后并没有将父类成员完全赋值到子类中,而是通过引用关系访问调用
4、子类中可以定义独有的成员属性和方法
5、子类中定义的成员和父类成员如果相同,则优先使用子类成员
6、子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用, 可以使用 [父类名.父类成员] 的格式来调用父类成员,也可以使用super().父类成员的 格式来调用
代码如下:
class A():
def work(self):
print('工作')
class B(A):
del work(self):
A.work(self) --->在子类中扩展父类的成员功能(方法1)
super().work() --->在子类中扩展父类的成员功能(方法2)
print('B类的工作')
e.继承变量函数的查找顺序问题
优先查找自己的变量
没有则查找父类
构造函数如果本类中没有定义,则自动查找调用父类构造函数
如果本类有定义,则不在继续向上查找
f.构造函数(应该也是魔术)
是一类特殊的函数,在类进行实例化之前进行调用
语法:
class A():
def __init__(self):
print('这是一个构造函数,在类初始化的时候自动调用执行!!!')
如果定义了构造函数,则实例化时使用构造函数,不查找父类构造函数
如果没定义,则自动查找父类构造函数
如果子类没定义,父类的构造函数带参数,则构造对象时的参数应该按父类参数构造
h.super
super不是关键字, 而是一个类
super的作用是获取MRO(MethodResolustionOrder)列表中的第一个类
super于父类直接没任何实质性关系,但通过super可以调用到父类
super使用两个方,参见在构造函数中调用父类的构造函数
i.单继承和多继承
单继承:每个类只能继承一个类
多继承,每个类允许继承多个类
j.单继承和多继承的优缺点
单继承:
传承有序逻辑清晰语法简单隐患少呀
功能不能无限扩展,只能在当前唯一的继承链中扩展
多继承:
优点:类的功能扩展方便
缺点:继承关系混乱
k.菱形继承/钻石继承问题:
多个子类继承自同一个父类,这些子类由被同一个类继承,于是继承关系图形成一个菱形图谱
关于多继承的MRO:
MRO就是多继承中,用于保存继承顺序的一个列表
python本身采用C3算法来多多继承的菱形继承进行计算的结果
MRO列表的计算原则:
子类永远在父类前面
如果多个父类,则根据继承语法中括号内类的书写顺序存放
如果多个类继承了同一个父类,孙子类中只会选取继承语法括号中第一个父类的父类
l.构造函数:
在对象进行实例化的时候,系统自动调用的一个函数叫构造函数,通常此函数用来对实例对象进行初始化,顾名
构造函数一定要有,如果没有,则自动向上查找,按照MRO顺序,直到找到为止
多态
3.多态
多态就是同一个对象在不同情况下有不同的状态出现
多态不是语法,是一种设计思想
多态性: 一种调用方式,不同的执行效果
多态: 同一事物的多种形态,动物分为人类,狗类,猪类
多态和多态性的区别
1、Mixin设计模式
主要采用多继承方式对类的功能进行扩展
2、我们使用多继承语法来实现Minxin
3、使用Mixin实现多继承的时候非常小心
首先他必须表示某一单一功能,而不是某个物品
职责必须单一,如果由多个功能,则写多个Mixin
Mixin不能依赖于子类的实现
子类及时没有继承这个Mixin类, 也能照样工作,只是缺少了某个功能
4、优点
使用Mixin可以在不对类进行任何修改的情况下,扩充功能
可以方便的组织和维护不同功能组件的划分
可以根据需要任意调整功能类的组合
可以避免创建很多新的类,导致类的继承混乱
类的相关函数:
(在类的级别上去操作类)
issubclass:检测一个类是否是另一个类的子类
isinstance:检测一个对象是否是一个类的实例
hasattr:检测一个对象是否由成员xxx
getattr: get attribute
setattr: set attribute
delattr: delete attribute
dir: 获取对象的成员列表
类的成员描述符(属性)
类的成员描述符是为了在类中对类的成员属性进行相关操作而创建的一种方式
get: 获取属性的操作
def fget():
print()
set:修改或者添加属性操作(在修改成员后触发该方法)
def fset():
print()
delete: 删除属性的操作(在删除成员的时候会自动调用该方法)
def fdel():
print()
如果想使用类的成员描述符,大概有三种方法
使用类实现描述器
使用属性修饰符
使用property函数
property函数很简单
property(fget, fset, fdel, doc)
无论哪种修饰符都是为了对成员属性进行相应的控制
类的方式: 适合多个类中的多个属性共用用一个描述符
property:使用当前类中使用,可以控制一个类中多个属性
属性修饰符: 使用于当前类中使用,控制一个类中的一个属性
6. 类的内置属性
__dict__:以字典的方式显示类的成员组成 __doc__: 获取类的文档信息 __name__:获取类的名称,如果在模块中使用,获取模块的名称 __bases__: 获取某个类的所有父类,以元组的方式显示
7. 类的常用魔术方法
- 魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发
- 魔术方法的统一的特征,方法名被前后各两个下滑线包裹
- 操作类
-
- __init__: 构造函数
- __new__: 对象实例化方法,此函数较特殊,一般不需要使用
- __call__: 对象当函数使用的时候触发
- __str__: 当对象被当做字符串使用的时候调用
- __repr__: 返回字符串,跟__str__具体区别请百度
- 描述符相关
-
- __set__
- __get__
- __delete__
- 属性操作相关
-
- __getattr__: 访问一个不存在的属性时触发
- __setattr__: 对成员属性进行设置的时候触发
-
-
- 参数:
-
-
-
-
- self用来获取当前对象
- 被设置的属性名称,以字符串形式出现
- 需要对属性名称设置的值
-
-
-
-
- 作用:进行属性设置的时候进行验证或者修改
- 注意: 在该方法中不能对属性直接进行赋值操作,否则死循环
- 参看案例
-
- 运算分类相关魔术方法
-
- __gt__: 进行大于判断的时候触发的函数
-
-
- 参数:
-
-
-
-
- self
- 第二个参数是第二个对象
- 返回值可以是任意值,推荐返回布尔值
- 案例
-
-
8. 类和对象的三种方法
- 实例方法
-
- 需要实例化对象才能使用的方法,使用过程中可能需要截止对象的其他对象的方法完成
- 静态方法
-
- 不需要实例化,通过类直接访问
- 类方法
-
- 不需要实例化
10. 抽象类
- 抽象方法: 没有具体实现内容的方法成为抽象方法
- 抽象方法的主要意义是规范了子类的行为和接口
- 抽象类的使用需要借助abc模块
import abc
- 抽象类:包含抽象方法的类叫抽象类,通常成为ABC类
- 抽象类的使用
-
- 抽象类可以包含抽象方法,也可以包含具体方法
- 抽象类中可以有方法也可以有属性
- 抽象类不允许直接实例化
- 必须继承才可以使用,且继承的子类必须实现所有继承来的抽象方法
- 假定子类没有是现实所有继承的抽象方法,则子类也不能实例化
- 抽象类的主要作用是设定类的标准,以便于开发的时候具有统一的规范
11. 自定义类
- 类其实是一个类定义和各种方法的自由组合
- 可以定义类和函数,然后自己通过类直接赋值
- 可以借助于MethodType实现
- 借助于type实现
- 利用元类实现- MetaClass
-
- 元类是类
- 备用来创造别的类