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面向对象编程中的元类使用。