面向对象之:继承(inheritance)

面向对象之:继承(inheritance)

1.什么是面向对象的继承

继承是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。

简单的说,都通过子承父业,合法继承资产,如果你是独生子,那么不出意外你会继承你父母的全部财产。

简单的继承例子:

class Animal:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
class Dog:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
#继承
class Animal:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
class Dog(Animal):
    pass
2.继承的特点
  • 增加了类与类的耦合性

  • 减少重复代码

3.继承的分类

在上面的例子中

Animal称父类,基类,超类

Dog称子类,派生类

继承

  • 单继承

  • 多继承

4.单继承

简单用法

class Animal:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
class Dog(Animal):
    def run(self):
        print(f"{self.name}正在跑。。。")
dog1=Dog('大黄',8,'母')
dog1.run()

这个例子中,dog属于动物类,而动物类有共同的属性name,age,sex,如果我们每个动物类都初始化name,age,sex代码冗余,效率低。

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

class Animal:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
class Dog(Animal):
    def __init__(self,name,age,sex,speed):
        super().__init__(name,age,sex)
        self.speed=speed
    def run(self):
        print(f"{self.name}正在以{self.speed}迈的速度跑。。。")
dog1=Dog('大黄',8,'母',35)
dog1.run()
5.多继承

话不多说上代码,自己体会一下

class Fairy:#神仙类
    def fly(self):
        print('神仙会飞。。。')
class Monkey: #猴子类
    def eat(self):
        print("猴子偷桃吃!!!")
class SunMonkey(Fairy,Monkey):
    pass
sun1=SunMonkey()
sun1.fly()
sun1.eat()

看过西游记的都知道,孙悟空既是猴子又是神仙,在上面代码中,他自然就继承了两个类中的方法这就是简单的多继承。

那既然继承两个类,那就要涉及到继承顺序的问题。

新式类的多继承

这里需要补充一下python中类的种类:

在python2x版本中存在两种类.:

  • ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.

  • ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。

python3x版本中只有一种类:

  • python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

mro序列-C3算法

mro是一个有序列表,在类被创建是就计算出来了

通用公式

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

其中merge操作是c3算法的核心

下面介绍一些关于公式的知识

表头与表尾

  • 表头--列表的第一个元素

  • 表尾--列表中表头以外元素的集合,(有可能为空)

下面我计算一个来演示一下计算过程

class A(object):
    pass
​
class B(A):
    pass
​
class C(A):
    pass
​
class D(A):
    pass
​
class E(B,C):
    pass
​
class F(C,D):
    pass
​
class G(D):
    pass
​
class H(E,F):
    pass
​
class I(F,G):
    pass

 

公式:

mro(K(H,I))=[K]+merge(mro(H),mro(I),[H,I])
​
计算mro(H)--由上面的代码看出H类继承E,F两个类
mro(H(E,F))=[H]+merge(mro(E),mro[F],[E,F])
​
再分别计算mro(H)中的mro(E),mro(F)
mro(E(B,C))=[E]+merge(mro(B),mro(c),[B,C])
        有代码看出B类由继承A类
        =[E]+merge([B,A],[C,A],[B,C])
#就这样依次计算出mro(E),mro(F)进而计算出mro(H),在按照这个思路计算出mro(I)..................
最后得到:
    mro(K(H,I))=[K]+merge([H,E,B,F,C,D,A],[I,F,C,G,D,A],[H,I])
再依照merge操作
最后计算出结果如下:
    [K,H,E,B,I,F,C,G,D,A]
这就是这些继承类的执行顺序

merge操作实例

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

这下就计算OK了。

最后说一下python提供的方法计算执行顺序

print(mro(A))

上面代码的结果如下

[<class '__main__.K'>, <class '__main__.H'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.I'>, 
<class '__main__.F'>,
<class '__main__.C'>, <class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]

看到这很多人就会疑惑了,既然有python的方法,哪还手动推导干嘛呢?

那我想问你,当你去笔试的时候,没有电脑你怎么办呢?所以这个简单的算法要会。

上一篇:python-从Django中的其他模型填充模型?


下一篇:有关扩展类的PHP继承问题