分享

python类中super()与

 昵称70813452 2020-07-11

子类继承的初始化规则

首先需要说明关于类继承方面的初始函数__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")
        
项目 方法
r95Xb 6fEaz3069
A0Ukw 2005-12-07 06:41:30
6FBlU 抖音怎么玩
mRr6R 2005.08.20 21-38-32
Se19O 4QO3M4741
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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多