zoukankan      html  css  js  c++  java
  • python之面向对象继承

    一、面向对象之继承

    1. 面向对象三大特性

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

    2. 继承

      • 定义

        ​ 如果一个类别A“继承自”另一个类别B就把这个A称为“B的子类”或“B的派生类”,而把B称为“A的父类”也可以称为“B是A的基类或超类”。

        ​ 继承可以使的子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。

        ​ 在子类继承父类的同时,可以重新定义某些属性,并重写某些方法(即覆盖父类的原有属性和方法)使其获得与父类不同的功能,也可为子类追加新的属性和方法

      • 特点

        1. 增加了类的耦合性(耦合性不宜多,易精)
        2. 减少代码重复性
        3. 是的代码更加规范化,合理化
      • 分类

        继承可以分为单继承多继承

        在python2中x版本中存在两种类:

        ​ 一个叫经典类,python2.2之前一直使用的使经典类,经典类在基类的根什么都不写

        ​ 一个叫新式类,python2.2之后出现了新式类,新式类在基类的根是object类

        python3中使用的都是新式类,如果基类谁都不继承,那这个类默认继承object

    3. 单继承

      • 类名,对象执行父类方法

        • 从类名执行父类的属性和方法

          class Animal(object):
              live = '有生命的'
              def __init__(self,name,age,sex):
                  self.name = name
                  self.age = age
                  self.sex = sex
              def eat(self):
                  print(f'self--->{self}')
                  print('动物需要进食')
          class Person(Animal):
              pass
          
          print(Person.live)	# 有生命的
          print(Person.__dict__)
          # {'__module__': '__main__', '__doc__': None}
          Person.eat(12)
          # self--->12
          # 动物需要进食
          
        • 从对象执行父类的属性和方法

          class Animal(object):
              live = '有生命的'
              def __init__(self,name,age,sex):
                  self.name = name
                  self.age = age
                  self.sex = sex
              def eat(self):
                  print(f'self--->{self}')
                  print('动物需要进食')
          class Person(Animal):
              pass
          p1 = Person('dsb',21,'laddy_boy')
          print(p1.__dict__)
          # {'name': 'dsb', 'age': 21, 'sex': 'laddy_boy'}
          print(p1.live)
          # 有生命的
          # self---><__main__.Person object at 0x000001E8FC22F4E0>
          p1.eat()
          # 动物需要进食
          

          注意:子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)

      • 执行顺序

        对象查找顺序先从对象空间找名字,再到子类找名字,然后去父类找名字

      • 同时执行类以及父类方法

        • 方法一

          class Animal:
              live = '有生命的'
              def __init__(self,name,age,sex):
                  self.name = name
                  self.age = age
                  self.sex = sex
              def eat(self):
                  print('动物都需要进食')
          class Person(Animal):
              def __init__(self,name,age,sex,hobby):
                  Animal.__init__(self,name,age,sex)#调用Animal的__init__方法,当Person实例化时,将name,age,sex传递给Animal
                  self.hobby = hobby
              def eat(self):
                  print('人类需要进食')
          p1 = Person('铁憨憨',23,'男','锤人')
          print(p1.__dict__)
          # {'name': '铁憨憨', 'age': 23, 'sex': '男', 'hobby': '锤人'}
          

          在对象的空间中调用父类的__init__方法,通过子类的实例化将父类__init__所需的参数传进去。

        • 方法二

          class Animal:
              live = '有生命的'
              def __init__(self,name,age,sex):
                  self.name = name
                  self.age = age
                  self.sex = sex
              def eat(self):
                  print('动物都需要进食')
          class Person(Animal):
              def __init__(self,name,age,sex,hobby):
                  super().__init__(name,age,sex)
                  self.hobby = hobby
              def eat(self):
                  print('人类需要进食')
                  super().eat()
          p1 = Person('铁憨憨',23,'男','锤人')
          p1.eat()
          # 人类需要进食
          # 动物都需要进食
          

          通过super().__init__的方式在对象空间中添加父类的属性

    4. 多继承

      class God:
          def __init__(self,name):
              self.name = name
          def fly(self):
              print('会飞')
          def climb(self):
              print('神仙累了也需要爬树')
      class Monkey:
          def __init__(self,sex):
              self.sex = sex
          def climb(self):
              print('爬树')
      class MonkeySun(God,Money):
          pass
      sun = MonkeySun()
      sun.climb()
      # 神仙累了也需要爬树
      
      • 经典类的多继承

        虽然在python3中已经不存在经典类了. 但是经典类的MRO最好还是学⼀学. 这是⼀种树形结构遍历的⼀个最直接的案例,代码如下:

        class A:
            pass
        class B(A):
            pass
        class C(A):
            pass
        class D(B, C):
            pass
        class E:
            pass
        class F(D, E):
            pass
        class G(F, D):
            pass
        class H:
            pass
        class Foo(H, G):
            pass
        

        继承关系图如下:

        在经典类中采⽤的是深度优先,遍历方案。⼀条路走到头,然后再回来,继续找下⼀个。

      • 新式类的多继承

        代码如下:

        class A:
            pass
        
        class B(A):
            pass
        
        class C(A):
            pass
        
        class D(B, C):
            pass
        
        class E:
            pass
        
        class F(D, E):
            pass
        
        class G(F, D):
            pass
        
        class H:
            pass
        
        class Foo(H, G):
            pass
        print(Foo.mro())
        
        • mro序列

          MRO是一个有序列表L,在类被创建时就计算出来。
          通用计算公式为:

          mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
          (其中Child继承自Base1, Base2)
          

          如果继承至一个基类:class B(A)
          这时B的mro序列为

          mro( B ) = mro( B(A) )
          = [B] + merge( mro(A) + [A] )
          = [B] + merge( [A] + [A] )
          = [B,A]
          

          如果继承至多个基类:class B(A1, A2, A3 …)
          这时B的mro序列

          mro(B) = mro( B(A1, A2, A3 …) )
          = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
          = ...
          

          计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

        • 表头和表尾

          表头:
            列表的第一个元素

          表尾:
            列表中表头以外的元素集合(可以为空)

          示例
            列表:[A, B, C]
            表头是A,表尾是B和C

        • 列表之间的+操作

          +操作:

          [A] + [B] = [A, B]
          (以下的计算中默认省略)
          ---------------------

          merge操作示例:

          如计算merge( [E,O], [C,E,F,O], [C] )
          有三个列表 :  ①      ②          ③
          
          1 merge不为空,取出第一个列表列表①的表头E,进行判断                              
             各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
          2 取出列表②的表头C,进行判断
             C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
             merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
          3 进行下一次新的merge操作 ......
          --------------------- 
          

          继承关系图如下:

          计算mro(A)方式:

          mro(A) = mro( A(B,C) )
          
          原式= [A] + merge( mro(B),mro(C),[B,C] )
          
            mro(B) = mro( B(D,E) )
                   = [B] + merge( mro(D), mro(E), [D,E] )  # 多继承
                   = [B] + merge( [D,O] , [E,O] , [D,E] )  # 单继承mro(D(O))=[D,O]
                   = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出并删除D
                   = [B,D,E] + merge([O] ,  [O])
                   = [B,D,E,O]
          
            mro(C) = mro( C(E,F) )
                   = [C] + merge( mro(E), mro(F), [E,F] )
                   = [C] + merge( [E,O] , [F,O] , [E,F] )
                   = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳过O,拿出并删除
                   = [C,E,F] + merge([O] ,  [O])
                   = [C,E,F,O]
          
          原式 = [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
              = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])
              = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳过E
              = [A,B,D,C] + merge([E,O],  [E,F,O])
              = [A,B,D,C,E] + merge([O],    [F,O])  # 跳过O
              = [A,B,D,C,E,F] + merge([O],    [O])
              = [A,B,D,C,E,F,O]
          
  • 相关阅读:
    mac连接windows远程桌面
    苹果应用ipa图片提取
    001android eclipse 自动生成的程序
    输入10 个数并对10个数进行排序
    一个偶数总能表示为两个素数之和
    Ajax基础判断当前用户名是否已经存在
    求0—7所能组成的奇数个数
    有包的程序在命令行如何运行
    求1/2+1/4+...+1/n
    最大公约数和最小公倍数
  • 原文地址:https://www.cnblogs.com/yaoqi17/p/11159737.html
Copyright © 2011-2022 走看看