python继承(super()、多继承、钻石继承)

python继承简介

Java只支持单继承多接口模式。Python支持多继承模式。
在多继承模式中有个难题就是钻石继承也叫做菱形继承
下图就是钻石继承的例子。
一般来说,Leaf类初始化时会初始化Medium1类和Medium2类,然后Medium1类初始化时会初始化Base类,Medium2类初始化时也会初始化Base类,所以这就导致Leaf类初始化时对Base类进行了两次初始化操作。python是通过super()来解决这个问题的。
在这里插入图片描述

还是首先来点干货,子类初始化时在__init__方法里如何调用父类的初始化方法。有如下两种方法

  • 父类名称.__init__(self,参数1,参数2,...)
  • super(子类,self).__init__(参数1,参数2,....)

关于super()我们可以通过help(super)函数查看其使用说明。
在这里插入图片描述
super()就等价于super(__class__, <first argument>),即super(当前class, self)
super(type, obj) -> bound super object; requires isinstance(obj, type) ,其中第一个参数是开始寻找父类的起始点(起始但不包括),第二个参数是需要一个对应第一个type的实例,即满足isinstance(obj,type),这个方法将返回第一个满足继承关系的类,寻找顺序遵从type.__mro__属性顺序(mro将类的树形继承关系变成了一个list)

下面展示一个例子,类之间的关系图如下所示。
Student类分别继承于Person类和IdCard类,Person类又继承于Human类,当然Human类和IdCard类都会继承于object类(这里就不显示出来了)。
可通过Student.mro()查看Student类的继承关系(变成了list)。
在这里插入图片描述

特别注意,由于多继承的缘故,__init__方法的参数最好是写成可选参数。
Student类的__init__方法中super(Human, self).__init__(*args)IdCard.__init__(self, *args)是等价的,这也可以从mro列表顺序看出来。Student类的__init__方法也说明了当子类继承多个父类时,如果有需要的话,可以在子类的__init__方法显示调用多个父类的__init__方法。

# -*- coding: UTF-8 -*-

class Human(object):

    def __init__(self, sex):
        print("Human init start")
        self._sex = sex
        print("Human init end")

    def __str__(self):
        return "Human sex is {}".format(self._sex)

class Person(Human):

    def __init__(self, name, age, *args):
        print("Person init start")
        self._name = name
        self._age = age
        super().__init__(args[0])
        print("Person init end")


class IdCard(object):

    def __init__(self, *args):
        print("IdCard init start")
        self._id_card = args[-1]
        print("IdCard init end")

class Student(Person, IdCard):

    def __init__(self, grade, *args):
        print("Student init start")
        self._grade = grade
        super().__init__(*args)
        print(__class__)
        # super(Human, self).__init__(*args)  # 从Human开始起查找,但是不包括起点
        IdCard.__init__(self, *args)  # 这种方法也可以
        print("Student init end")

    def __str__(self):
        s = "sex={}\tname={}\tage={}\tgrade={}\tidCard={}".format(self._sex, self._name, self._age, self._grade, self._id_card)
        return s

# mro是method resolution order, 表示了类继承体系中的成员解析顺序
# 将继承的树关系变成了一个list
# [<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Human'>, <class '__main__.IdCard'>, <class 'object'>]
print(Student.mro())
s = Student(100, "patrick", 26, "male", "programmer")
print(s)

运行结果如下
在这里插入图片描述

在设计类时,类的继承关系一定要设计好设计清楚,要不然真是个大坑,特别是多继承条件下!!!

这里需要再次说明的是,__init__方法只是对实例对象做了属性的初始化,并不等同于Java里的new Student(),在python里是通过__new__方法创建对象的,创建对象成功后再调用__init__方法做属性的初始化。
在创建对象时可以通过元类来定制化创建,动态地给对象添加属性或方法,这里就可以参考python面向对象编程中的元类使用

参考网址

python如何解决钻石继承难题
python菜鸟教程----子类如何继承父类初始化函数说明
python中关于子类调用父类初始化函数的说明

发布了31 篇原创文章 · 获赞 0 · 访问量 1792

猜你喜欢

转载自blog.csdn.net/qq_23120963/article/details/105452376