面向对象:继承

一:什么面向对象的继承?

比较官方的说法就是:

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

字面意思就是:子承父业,合法继承家产,就是如果你是独生子,而且你也很孝顺,不出意外,你会继承你父母所有家产,他们的所有财产都会由你使用(败家子儿除外)。

那么用一个例子来看一下继承:

img View Code

继承的有点也是显而易见的:

1,增加了类的耦合性(耦合性不宜多,宜精)。

2,减少了重复代码。

3,使得代码更加规范化,合理化。

二 继承的分类。

就向上面的例子:

扫描二维码关注公众号,回复: 7058683 查看本文章

Aminal 叫做父类,基类,超类。
Person Cat Dog: 子类,派生类。
继承:可以分单继承,多继承

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
  ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

三,单继承。

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

img 类名,对象分别调用父类方法

3.2 执行顺序

img 执行顺序

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

方法一:

如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:

父类.func(对象,其他参数)

举例说明:

复制代码

class Aniaml(object):
    type_name = '动物类'
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print('吃东西')

class Person(Aniaml):
    def __init__(self,name,sex,age,mind):
        '''
        self = p1
        name = '春哥'
        sex = 'laddboy'
        age = 18
        mind = '有思想'
        '''
        # Aniaml.__init__(self,name,sex,age)  # 方法一
        self.mind = mind

    def eat(self):
        super().eat()
        print('%s 吃饭'%self.name)
class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass

# 方法一: Aniaml.__init__(self,name,sex,age)
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

# 对于方法一如果不理解:
# def func(self):
#     print(self)
# self = 3
# func(self)

复制代码

方法二:

利用super,super().func(参数)

复制代码

class Aniaml(object):
    type_name = '动物类'
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print('吃东西')

class Person(Aniaml):
    def __init__(self,name,sex,age,mind):
        '''
        self = p1
        name = '春哥'
        sex = 'laddboy'
        age = 18
        mind = '有思想'
        '''
        # super(Person,self).__init__(name,sex,age)  # 方法二
        super().__init__(name,sex,age)  # 方法二
        self.mind = mind

    def eat(self):
        super().eat()
        print('%s 吃饭'%self.name)
class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

复制代码

单继承练习题:

img View Code

四,多继承

复制代码

class ShenXian: # 神仙
    def fei(self):
        print("神仙都会⻜")
class Monkey: # 猴
    def chitao(self):
        print("猴⼦喜欢吃桃⼦")
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是⼀只猴
    pass
sxz = SunWukong() # 孙悟空
sxz.chitao() # 会吃桃⼦
sxz.fei() # 会⻜

复制代码

  此时, 孙悟空是⼀只猴⼦, 同时也是⼀个神仙. 那孙悟空继承了这两个类. 孙悟空⾃然就可以执⾏这两个类中的⽅法. 多继承⽤起来简单. 也很好理解. 但是多继承中, 存在着这样⼀个问题. 当两个⽗类中出现了重名⽅法的时候. 这时该怎么办呢? 这时就涉及到如何查找⽗类⽅法的这么⼀个问题.即MRO(method resolution order) 问题. 在python中这是⼀个很复杂的问题. 因为在不同的python版本中使⽤的是不同的算法来完成MRO的.

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
  ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

4.1经典类的多继承

虽然在python3中已经不存在经典类了. 但是经典类的MRO最好还是学⼀学. 这是⼀种树形结构遍历的⼀个最直接的案例. 在python的继承体系中. 我们可以把类与类继承关系化成⼀个树形结构的图. 来, 上代码:

img 代码示例

对付这种mro画图就可以:

img

继承关系图已经有了. 那如何进⾏查找呢? 记住⼀个原则. 在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.

img

图中每个圈都是准备要送鸡蛋的住址. 箭头和⿊线表⽰线路. 那送鸡蛋的顺序告诉你入⼝在最下⾯R. 并且必须从左往右送. 那怎么送呢?

img

如图. 肯定是按照123456这样的顺序来送. 那这样的顺序就叫深度优先遍历. ⽽如果是142356呢? 这种被称为⼴度优先遍历. 好了. 深度优先就说这么多. 那么上⾯那个图怎么找的呢? MRO是什么呢? 很简单. 记住. 从头开始. 从左往右. ⼀条路跑到头, 然后回头. 继续⼀条路跑到头. 就是经典类的MRO算法.

类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜对了么?

4.2新式类的多继承

4.2.1 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算法的核心。

4.2.2. 表头和表尾
表头:
  列表的第一个元素

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

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

4.2.3. 列表之间的+操作
+操作:

[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操作 ......
--------------------- 

复制代码

img

计算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]
--------------------- 

复制代码

C3就是把我们多个类产⽣的共同继承留到最后去找. 所以. 我们也可以从图上来看到相关的规律.. 但是如果没有所谓的共同继承关系. 那⼏乎就当成是深度遍历就可以了

猜你喜欢

转载自www.cnblogs.com/qidaii/p/11373594.html