子类继承的初始化规则
首先需要说明关于类继承方面的初始函数__init__()
:
- 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用,但是需要在实例化子类的对象时传入父类初始化函数对应的参数
- 如果子类定义了自己的初始化函数,而在子类中没有显式调用父类的初始化函数,则父类的属性不会被初始化,
- 如果子类定义了自己的初始化函数,在子类中显示调用父类,子类和父类的属性都会被初始化
对于情况1,如下:
class Base:
def __init__(self, name, id = 2):
self.name = name
self.id = id
print("Base create")
print("id = ", self.id)
def func(self):
print("base fun")
class childA(Base):
# def __init__(self):
# print("childA create")
# Base.__init__(self, "A") # 父类名硬编码到子类中
def funA(self):
print("funA")
A = childA('john',id=2) # 必须手动传入,否则A还是不会有name和id对象
print(A.name, A.id)
结果为:
Base create
id = 2
john 2
对于情况2,如下:
class Base:
def __init__(self, name, id = 2):
self.name = name
self.id = id
print("Base create")
print("id = ", self.id)
def func(self):
print("base fun")
class childA(Base):
def __init__(self):
print("childA create")
# Base.__init__(self, "A") # 父类名硬编码到子类中
def funA(self):
print("funA")
A = childA()
print(A.name, A.id)
结果显示为:
AttributeError: 'childA' object has no attribute 'name'
对于情况3,如下:
class Base:
def __init__(self, name, id = 2):
self.name = name
self.id = id
print("Base create")
print("id = ", self.id)
def func(self):
print("base fun")
class childA(Base):
def __init__(self):
print("childA create")
Base.__init__(self, "A") # 父类名硬编码到子类中
def funA(self):
print("funA")
结果为:
Base create
id = 2
john 2
其中Base.__init__(self, "A")
就是朴素的子类调用父类的初始化,初始化时必须填入位置变量name
即这里的"A"
,而关键字变量id
可选。
super()
注意super()只能用在新式类中(当然用python3的人不用担心这个问题),并且在单继承类中super()跟单纯的__init__()没什么区别,如下:
class Base:
def __init__(self, name, id = 2):
self.name = name
self.id = id
print("Base create")
print("id = ", self.id)
def func(self):
print("base fun")
class childA(Base):
def __init__(self):
print("childA create")
Base.__init__(self, "A") # 父类名硬编码到子类中
def funA(self):
print("funA")
class childB(Base):
def __init__(self):
print("childB create")
# super(childB, self).__init__('B') # super,将子类名和self传递进去
super().__init__('B',id=3) # python3可以直接简化成这个形式
self.id = 3
另外需要注意的是super不是父类,而是继承顺序的下一个类,如下是多类继承的情况:
class Base(object):
def __init__(self):
print 'Base create'
class childA(Base):
def __init__(self):
print 'enter A '
# Base.__init__(self)
super(childA, self).__init__()
print 'leave A'
class childB(Base):
def __init__(self):
print 'enter B '
# Base.__init__(self)
super(childB, self).__init__()
print 'leave B'
class childC(childA, childB):
pass
c = childC()
print c.__class__.__mro__
输出结果如下:
enter A
enter B
Base create
leave B
leave A
(<class '__main__.childC'>, <class '__main__.childA'>, <class '__main__.childB'>, <class '__main__.Base'>, <type 'object'>)
supder和父类没有关联,因此执行顺序是A —> B—>—>Base,执行过程相当于:初始化childC()时,先会去调用childA的构造方法中的 super(childA, self).init(), super(childA, self)返回当前类的继承顺序中childA后的一个类childB;然后再执行childB().init(),这样顺序执行下去。
在多重继承里,如果把childA()中的 super(childA, self).init() 换成Base.init(self),在执行时,继承childA后就会直接跳到Base类里,而略过了childB:
enter A
Base create
leave A
(<class '__main__.childC'>, <class '__main__.childA'>, <class '__main__.childB'>, <class '__main__.Base'>, <type 'object'>)
super()复杂示例
下面举一个更复杂的例子帮助更好的理解super():
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * self.length + 2 * self.width
class Square(Rectangle):
def __init__(self, length):
super(Square, self).__init__(length, length)
class Triangle:
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
class RightPyramid(Triangle, Square):
def __init__(self, base, slant_height):
self.base = base
self.slant_height = slant_height
def area(self):
base_area = super().area()
perimeter = super().perimeter()
return 0.5 * perimeter * self.slant_height + base_area