派生

派生

【一】什么是派生

  • 派生是指子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法

【二】派生的方法

  • 子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找
  • 例如每个老师还有职称这一属性
  • 我们就需要在Teacher类中定义该类自己的__init__覆盖父类的
  • 当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

​ 举例:

派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找

方法一:

class People:
    school = '希望小学'

    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age


class Teacher(People):
    # 派生 : 派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找
    def __init__(self, name, sex, age, title):
        self.name = name
        self.sex = sex
        self.age = age
        self.title = title

    def teach(self):
        print('%s is teaching' % self.name)


# 只会找自己类中的__init__,并不会自动调用父类的
obj = Teacher('Tony', 'male', 18, '工人')

print(obj.name, obj.sex, obj.age, obj.title)
  • 很明显子类Teacher中__init__内的前三行又是在写重复代码
  • 若想在子类派生出的方法内重用父类的功能,有两种实现方式

【1】指名道姓的调用某一个类的函数

class People:
    school='希望小学'

    def  __init__(self,name,age):
        self.name=name
        self.age=age

    def tell(self):
        print('我叫%s,今年%s,我在%s上学。'%(self.name,self.age,self.school))

class student(People):
    def __init__(self,name,age,title):
        #父类的属性
        People.__init__(self,name,age)
        self.title=title

obj=student('张三',20,'学生')
print(obj.name,obj.age,obj.title)
#张三 20 学生

【2】超类(super())

  • 调用super()会得到一个特殊的对象
  • 该对象专门用来引用父类的属性
  • 且严格按照MRO规定的顺序向后查找
class People:
    school='希望小学'

    def  __init__(self,name,age):
        self.name=name
        self.age=age


class student(People):

    def __init__(self,name,age,title):
        super().__init__(name,age)
        self.title=title


obj=student('张三',20,'学生')
print(obj.name,obj.age,obj.title)
#张三 20 学生
  • 注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

【3】小结

  • 这两种方式的区别是:
    • 方式一是跟继承没有关系的,而方式二的super()是依赖于继承的
    • 并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
    • mro()
# A没有继承B
class A:
    def test(self):
        super().test()


class B:
    def test(self):
        print('from B')


class C(A, B):
    pass


# 在代码层面A并不是B的子类
# 但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

obj = C()

# 属性查找的发起者是类C的对象obj
# 所以中途发生的属性查找都是参照C.mro()
obj.test()
# from B
  • obj.test()首先找到A下的test方法
    • 执行super().test()会基于MRO列表(以C.mro()为准)当前所处的位置继续往后查找()
    • 然后在B中找到了test方法并执行。
  • 关于在子类中重用父类功能的这两种方式
    • 使用任何一种都可以
    • 但是在最新的代码中还是推荐使用super()
#指名道姓
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        A.__init__(self)


class C(A):
    def __init__(self):
        print('C的构造方法')
        A.__init__(self)


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        B.__init__(self)
        C.__init__(self)

    pass
f1=D() #A.__init__被重复调用
'''
D的构造方法
B的构造方法
A的构造方法
C的构造方法
A的构造方法
'''
#使用super()
class A:
    def __init__(self):
        print('A的构造方法')
class B(A):
    def __init__(self):
        print('B的构造方法')
        super(B,self).__init__()


class C(A):
    def __init__(self):
        print('C的构造方法')
        super(C,self).__init__()


class D(B,C):
    def __init__(self):
        print('D的构造方法')
        super(D,self).__init__()

f1=D() #super()会基于mro列表,往后找
'''
D的构造方法
B的构造方法
C的构造方法
A的构造方法
'''
posted @ 2024-01-05 20:25  -半城烟雨  阅读(8)  评论(0编辑  收藏  举报