面向对象三大特性:封装、继承、多态(最全面最详细的解释)

office365打不开 📅 2025-11-21 18:11:13 👤 admin 👁️ 5149 ❤️ 511
面向对象三大特性:封装、继承、多态(最全面最详细的解释)

面向对象的三大特性

面向对象三大特性:封装、继承、多态封装概念:好处:

继承概念:目的:分类:type和object区分继承下的影响:资源的继承资源的使用资源的覆盖:相同属性,子类覆盖父类资源的累加

多态概念:多态在Python中的体现

补充抽象类抽象方法Python中的实现

面向对象三大特性:封装、继承、多态

封装

概念:

将一些属性和相关方法封装在一个对象中,对外隐藏内部具体实现细节。

内部实现,外界不需要关心,外界只需要根据”内部提供的接口“去使用就可以。

好处:

使用起来更加方便:因为已经把很多相关的功能,封装成一个整体,类似于像外界提供一个工具箱,针对于不同的场景,使用不同的工具箱就可以;

保证数据的安全:针对于安全级别高的数据,可以设置成”私有“,可以控制数据为只读(外界无法修改),也可以拦截数据的写操作(进行数据校验和过滤);

利于代码维护:如果后期,功能代码需要维护,则直接修改这个类内部代码即可;只要保证接口名称不变,外界不需要做任何代码修改。

继承

概念:

现实中的”继承“:子女继承父母的”财产资源“

编程中的”继承“:一个类”拥有“另外一个类的”资源“的方式之一;”拥有“:并不是资源的复制,编程双份资源,而是,资源的”使用权“;”资源“:指"非私有的"属性和方法。例如Dog类继承自Animal类

被继承的类:父类,基类,超类

继承的类:子类,派生类

目的:

方便资源重用

分类:

单继承:

概念:仅仅继承了一个父类。

class Father:

pass

class Chile(Father):

pass

多继承:

概念:继承了多个父类

class Father:

pass

class Mother:

pass

class Child(Father, Mother):

pass

查看父类的Child.__bases__

type和object区分

继承下的影响:

资源的继承

明确:在Python中,继承是指资源的使用权,所以,测试某个资源能否被继承,其实就是测试在子类当中,能不能访问到父类当中的资源

结论:Python中的继承并不是复制,只是使用资源。子类除不能访问父类的私有的属性和私有的方法外,其余均可继承(公有属性/方法,受保护属性/方法,内置方法)。

class Animal:

# 属性和方法

# 设置不同权限的属性和方法,继承当中进行测试

# 在子类当中能否访问到这些资源

a = 1 # 公共属性

_b = 2 # 保护属性

__c = 3 # 私有属性

def t1(self): # 公共方法

print('t1')

def _t2(self): # 保护方法

print('t2')

def __t3(self): # 私有方法

print('t3')

def __init__(self): #内置

print("init, Animal")

class Person(Animal):

def test(self):

print(id(self.a))

print(self.a)

print(self._b)

# print(self.__c)

self.t1()

self._t2()

# self.__t3()

self.__init__()

p = Person()

p.test()

print(id(Animal.a))

Animal.a = 666

p.test()

资源的使用

继承的几种形态:

单继承链无重叠的多继承链有重叠的多继承链 几种形态应该遵循的规则

单继承链

从下往上(A.age 先从A自身查找,若无,B查找,若无,C查找)A==>B==>C 无重叠的多继承链

单调原则,优先先到左侧查找。(A.age先从A自身查找,若无,B中查找,如无,D中查找,若无,C中查找,如无,E中查找)A==>B==>D==>C==>E 有重叠的多继承链

从下到上,单调原则,优先上一级左,右,然后上上级。(A.age先从A自身查找,若无,B中查找,如无,C中查找,如无,D中查找)A==>B==>C==>D

class B:

age = 3

class A(B):

pass

print(A.age)

A.age = 9

print(B.age)

print(A.age)

print(A.__dict__)

print(B.__dict__)

# 单继承链

class C:

pass

class B(C):

pass

class A(B):

pass

print(A.mro())

# 无重叠的多继承链

class E:

pass

class D:

pass

class C(E):

pass

class B(D):

pass

class A(B, C):

pass

print(A.mro())

# 菱形结构

class D:

pass

class C(D):

pass

class B(D):

pass

class A(B, C):

pass

print(A.mro())

针对几种标准原则的方案演化:

inspect模块inspect.getmro(A)

B.__mro__``B.mro()查找资源查找顺序

Python2.2之前:

仅仅存在经典类。MRO原则(深度优先–从左往右)。 问题:”有重叠的多继承“中,违背了”重写可用原则“A==>B==>D==>C。

Python2.2:产生了新式类,MRO原则:

经典类: 深度优先(从左到右) 新式类:

在深度优先(从左到右)的算法基础之上,优化了一部分:如果产生重复元素,会保留最后一个,并且更尊重基类出现的先后顺序。注意:并不是广度优先算法。问题:无法检测出有问题的继承;有可能还会违背”局部优先“原则。

Python2.3-2.7:

新式类经典类并存。MRO原则:经典类:深度优先(从左到右),新式类:C3算法。

Python3.x之后:

MRO原则–新式类–C3算法

概念补充:

MRO(Method Resolution Order):方法解析顺序

深度优先(栈):沿着一个继承链,尽可能的往深了去找。 具体步骤:

把根节点压入栈中。每次从栈中弹出一个元素,搜索所有在它下一级的元素把这些元素压入栈中(发现已经被处理,则略过)。重复第二个步骤到结束为止。

广度优先(队列):沿着继承链,尽可能往宽了去找。

具体算法步骤:

把根节点放到队列的末尾。每次从队列的头部去除一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾(发现已经被处理,则略过)。重复上面步骤。

C3算法:

真正步骤:

两个公式: L(object)=[object] L(子类(父类1,父类2)=[子类]+merge(L(父类1),L(父类2),[父类1,父类2])),

注意,+代表合并列表,merge算法:

类似拓扑排序,但并不是!如下图错误类关系,拓扑结构无法认证其错误问题。

资源的覆盖:相同属性,子类覆盖父类

根据优先级在优先级较高内的资源写相同的资源,形成一种资源被覆盖的现象。

分类:

属性的覆盖。方法重写。

原理: 在MRO的资源检索链当中,优先级比较高的类写了一个和优先级比较低的类一样的一个资源(属性或方法,而摒弃优先级比较低的资源,造成”覆盖“的假象。

注意事项:当调用优先级比较高的资源时,注意self的变化。谁调用,传递谁对象。

# 属性的覆盖

class E:

pass

class D:

age = 1

class C(E):

pass

class B(D):

age = 2

class A(B, C):

pass

print(A.age)

print(A.mro())

# 方法的重写

class E:

pass

class D:

def test(self):

print("D")

class C(E):

pass

class B(D):

def test(self):

print("B")

class A(B, C):

pass

print(A().test())

print(A().test)

print(A.mro())

# A().test 表明 调用A,self为A。

资源的累加

概念:在一个类的基础上,增加一些额外的资源

子类相比父类,多一些自己特有的资源

在被覆盖的方法基础之上,新增内容。

class B:

a1 = 1

class A(B):

a2 = 2

print(A.a1)

print(A.a2)

class B:

a = 1

def __init__(self):

self.b = 2

def test(self):

print('t')

@classmethod

def test1(cls):

print('t1')

@staticmethod

def test2():

print('t2')

class A(B):

c = 3

# def __init__(self): # 在存在自己的初始化函数__init__时,不会调用父类的初始化函数

# self.e = '666' # 解决办法:1: 直接复制父类的内容到子类初始化函数内

# 2.调用:通过类名;通过super

def __init__(self):

B.__init__(self)

self.e = '666'

def ttest(self):

print('t')

@classmethod

def ttest1(cls):

print('t1')

@staticmethod

def ttest2():

print('t2')

pass

p = A()

print(p.a)

print(p.b)

p.test()

p.test1()

p.test2()

print(p.c)

p.ttest()

p.ttest1()

p.ttest2()

p.d = 'xxx'

print(p.d)

print(p.e)

存在问题:

子类在存在自己的初始化函数__init__时,不会调用父类的初始化函数,造成父类的初始化函数参数无法及时返回到子类中。

解决办法:

直接复制父类的内容到子类初始化函数内调用:

通过类名(上述例子)通过super函数(建议使用)

# 创建菱形结构

class D(object):

def __init__(self):

print('d')

class B(D):

def __init__(self):

D.__init__(self)

print('d')

class C(D):

def __init__(self):

D.__init__(self)

print('c')

class A(B, C):

def __init__(self):

B.__init__(self)

C.__init__(self)

print('a')

B()

C()

A()

调用类这种方法会在A类中产生重复调用的情况,因此也存在着问题,但在经典类中只能使用这种方法。在新式类中可以采用super方法。

在低优先级类的方法中,通过"super"调用高优先级类的方法。

概念:是一个类,只有在新式类中有效。

作用:

起着代理的作用,帮我们完成以下任务沿着MRO链条,找到下一级节点,去调用对应的方法。注意不是严格的父类关系(菱形关系:A==>B==>C==>D,继承关系:A==>B,A==>C,B==>D,C==>D)

问题:

沿着谁的MRO链条?找谁的下一个节点?如何应对类方法,静态方法以及实例方法的传参问题?

语法原理:

* super(参数1[,参数2])

* 工作原理:

def super(cls, inst):

mro = inst.__class__.mro()

retun mro[mro.index(cls)+1]

* 问题解决:

沿着谁的MRO链条?答:参数2找谁的下一个节点?答:参数1如何应对类方法,静态方法以及实例方法的传参问题? 答:1.使用参数; 2.进行调用

常用具体语法形式:

# 适用于新式类

# Python2.2+

super(type,obj)->bound super object

# obj当作另外一个实例方法里的参数传递,type是类

super(type, type2)->bound super object

# 调用其他类的类方法,传递给类方法的第一个参数cls

# python 3+

super() #自动输入

通过super调用父类中的方法,注意:第一个参数是类函数,第二个参数是指传递的参数。第一个参数指查找哪一个类的下一个节点,使用第二个参数的MRO链条去调用后续的方法。

class B:

a = 1

def __init__(self):

self.b = 2

def test(self):

print('t')

@classmethod

def test1(cls):

print('t1')

@staticmethod

def test2():

print('t2')

class A(B):

c = 3

def __init__(self):

super(A, self).__init__()

self.e = '666'

def ttest(self):

print('t')

@classmethod

def ttest1(cls):

super(A, cls).test1() # cls或A 都可以,cls也在调用A类。 注意第一个参数为类名称,第二参数为传递参数

print('t1')

@staticmethod

def ttest2():

print('t2')

pass

p = A()

print(p.a)

print(p.b)

p.test()

p.test1()

p.test2()

print(p.c)

p.ttest()

p.ttest1()

p.ttest2()

p.d = 'xxx'

print(p.d)

print(p.e)

print(p.__dict__)

p.ttest1()

菱形问题解决

class D(object):

def __init__(self):

print('d')

class B(D):

def __init__(self):

super(B, self).__init__() # 切记不要用self.__class__代替B,因为self不一定是B中的类,有可能是子类传递过来的self

print('b')

class C(D):

def __init__(self):

super(C, self).__init__()

print('c')

class A(B, C):

def __init__(self):

super().__init__()

print('a')

# B()

# C()

A()

注意事项:

切记不要用super(self.__class__,self)代替cls,因为self不一定是cls中的类,有可能是子类传递过来的self不要通过类名和super混合使用调用资源。

多态

概念:

一个类,所延伸的多种形态;

调用时的多种形态:在继承的前提下;使用不同的子类,调用父类的同一个方法,产生不同的功能

class Animals:

def jiao(self):

pass

class Dog(Animals):

def jiao(self):

print('Wangwang')

class Cat(Animals):

def jiao(self):

print('Miaomiao')

def test(obj):

obj.jiao()

d = Dog()

c = Cat()

test(d)

test(c)

多态在Python中的体现

鸭子类型:

动态类型的一种风格只要一个对象,会走,会游泳,会叫;那么它就可以当作一个鸭子进行处理关注点在于对象的“行为和属性”,而非对象的“类型” 所以,在Python当中,没有真正意义上的多态;也不需要多态

补充

抽象类

一个抽象出来的类,并不是某一个具化的类

不能直接创建实例的类,创建会报错

抽象方法

抽象出来的一个方法(Animal)

不具备具体实现,不能直接调用;子类不是先会报错(jiao)

Python中的实现

无法直接支持,需要借助一个模块:import abc设置类的元类为abc.ABCMeta使用装饰器修饰抽象方法@abc.abcstractmethod

import abc

class Animals(object, metaclass=abc.ABCMeta):

@abc.abstractmethod

def jiao(self):

pass

@abc.abstractclassmethod

def test(cls):

print('cls')

class Dog(Animals):

def jiao(self):

print('Wangwang')

@classmethod

def test(cls):

print('Dogcls')

pass

class Cat(Animals):

def jiao(self):

print('Miaomiao')

def test(obj):

obj.jiao()

d = Dog()

# c = Cat()

test(d)

# test(c)

d.jiao()

d.test()

注意,在类中使用abc模块中的方法、静态方法和类方法时,声明之后必须要在运行的子类中也有相应的方法,否则无法运行。

相关推荐

Cathan's Traps (Diablo2)
office365打不开

Cathan's Traps (Diablo2)

📅 09-02 👁️ 2889
不想加班被强制加班怎么办
中国的365体育投注

不想加班被强制加班怎么办

📅 08-11 👁️ 5063
iOS 9 推送前你必须知道的几件事:iOS 9 升级指南
中国的365体育投注

iOS 9 推送前你必须知道的几件事:iOS 9 升级指南

📅 09-29 👁️ 9816