面向对象三大特性:封装、继承、多态(最全面最详细的解释) 您所在的位置:网站首页 最详细的洪荒资料是什么 面向对象三大特性:封装、继承、多态(最全面最详细的解释)

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

2024-07-04 14:50| 来源: 网络整理| 查看: 265

面向对象的三大特性 面向对象三大特性:封装、继承、多态封装概念:好处: 继承概念:目的:分类: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区分

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模块中的方法、静态方法和类方法时,声明之后必须要在运行的子类中也有相应的方法,否则无法运行。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有