继承与派生

继承

1.什么是继承

  继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类。

  -在Python中,一个子类可以继承多个父类。

  -在其他语言中,一个子类只能继承一个父类。

2.继承的作用

  减少代码的冗余。

3.如何实现继承

  1)先确认谁是子类,谁是父类

  2)在定义类子类时,子类名(父类名)

#父类
class Father1:
    x = 1
    pass
class Father2:
    pass
class Father3:
    pass
#子类
class Sub(Father1,Father2,Father3)
    pass
#子类.__bases__查看父类
print(Sub.__bases__)
print(Sub.x)

如何寻找继承关系

-确认谁是子类

  -sean对象 --->人子类 --->动物父类

  -小猪佩奇对象 --->猪子类 --->动物父类

  -哈士奇对象 --->狗子类 --->动物父类

-再确认谁是父类

  -动物类就是父类

  -得先抽象,再继承

    -抽取对象之间相似的部分,总结出类

    -抽取类之间相似的部分,总结出父类

问题:代码冗余
#老师类
class OldTeacher:
    school = 'oldboy'
    country = 'China'
    
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    #老师修改分数
    def change_score(self):
        print(f'老师{self.name}正在修改分数...')
#学生类
calss OldboyStudent:
    school = 'oldboy'
    country = 'China'
    
    def__init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.age = sex
    #学生选择课程
    def choose_course(self)
        print(f'学生{self.name}正在选择课程...')
stu1 = OldboyStudent('XXX',18,'male')
print(stu1.school,stu1.name,stu1.age,stu1.sex)

tea1 = OldboyTeacher('sean',18,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)

#解决代码冗余问题
class OldboyPeople:
    school = 'oldboy'
    country = 'China'
    
    def__init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        
#老师类
class OldboyTeacher(OldboyPeople):
    #老师修改分数
    def change_score(self):
        print(f'老师{self.name}正在修改分数...')

#学生类
class OldboyStudent(OldboyPeople):
    #学生选择课程
    def choose__course(self):
        print(f'学生{self.name}正在选择课程...')
        
stu1  OldboyStudent('XXX',18,'male')
print(stu1.school,stu1.name,stu1.age,stu1.sex)
tea1 = OldboyTeacher('sean',18,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)

注意:程序的执行顺序是由上到下,父类必须定义在子类的上方。

  -在继承背景下,对象数学的查找顺序:

    1.先从对象自己的名称空间中查找

    2.对象中没有,从子类的名称空间中查找。

    3.子类中没有,从父类的名称空间中查找,若父类没有,在会报错!

#父类
class Goo:
    x = 10
    pass
#子类
class Foo(Goo):
    x = 100
    pass
    
foo_obj = Foo()
#foo_obj.x = 1000   #对象添加属性的操作,并不是修改子类的属性
print(foo_obj.x)
print('对象的名称空间:',foo_obj.__dict__)
print('子类的名称空间: ',Foo.__dict__)
print('父类的名称空间: ',Goo.__dict__)

派生

派生:指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。

   若子类中的方法名与父类的相同,优先用子类的。

#父类
class Foo:
    def f1(self):
        print('from Foo.f1...')
        
    def f2(self):
        print('from Foo.f2...')
        self.f1()
#子类
class Bar(Foo):
    #重写
    def f1(self):
        print('from Bar.f1...')
    def func(self):
        print('from Bar.func...')
        
# bar_obj = Bar()
# bar_obj.f1()  # from Bar.f1..
# bar_obj.func()  # from Bar.func...
# bar_obj.f2()  # from Foo.f2...

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

问题:子类重写父类的__ init __导致代码更加冗余

class OldboyPeople:
    school = 'oldboy'
    
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
        
class OldboyTeacher(OldboyPeople):
        def __init__(self, name, age, sex, sal):
            self.name = name
            self.age = age
            self.sex = sex
            self.sal = sal
        
         def change_score(self):
         print(f'老师 {self.name} 修改分数...')
         
class OldboyStudent(OldboyPeople):

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

    def choose_course(self):
        print(f'学生 {self.name} 选择课程...')


tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
stu1 = OldboyStudent('XXX', 28, 'male', '凤姐')
print(tea1.name, tea1.age, tea1.sex, tea1.sal)
print(stu1.name, stu1.age, stu1.sex, stu1.girl)

'''
解决问题: 子类重用父类的属性,并派生出新的属性。
    两种方式:
        1.直接引用父类的__init__为其传参,并添加子类的属性。
        2.通过super来指向父类的属性。
            - super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。
            
        注意: 使用哪一种都可以,但不能两种方式混合使用。
'''
#方式一:
class OldboyPeople:
    school = 'oldboy'

    def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
        self.name = name
        self.age = age
        self.sex = sex


class OldboyTeacher(OldboyPeople):

    # tea1, 'tank', 17, 'male', 15000000
    def __init__(self, name, age, sex, sal):
        # self.name = name
        # self.age = age
        # self.sex = sex
        # 类调用类内部的__init__,只是一个普通函数
        # OldboyPeople.__init__(tea1, 'tank', 17, 'male')
        OldboyPeople.__init__(self, name, age, sex)
        self.sal = sal

    def change_score(self):
        print(f'老师 {self.name} 修改分数...')
class OldboyStudent(OldboyPeople):

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

    def choose_course(self):
        print(f'学生 {self.name} 选择课程...')


tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)


stu1 = OldboyStudent('XXX', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)

# 方式二:
class OldboyPeople:
    school = 'oldboy'

    # self == tea1
    def __init__(self, name, age, sex):  # self == tea1, name == 'tank', age == 17, sex == 'male'
        self.name = name
        self.age = age
        self.sex = sex


class OldboyTeacher(OldboyPeople):

    # tea1, 'tank', 17, 'male', 15000000
    def __init__(self, name, age, sex, sal):
        # super() ---> 特殊的对象 ---> 对象.属性 ---> 父类的名称空间
        # 会将调用类传入的对象当做第一个参数传给__init__()
        super().__init__(name, age, sex)
        self.sal = sal

    def change_score(self):
        print(f'老师 {self.name} 修改分数...')


class OldboyStudent(OldboyPeople):

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

    def choose_course(self):
        print(f'学生 {self.name} 选择课程...')


tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)


stu1 = OldboyStudent('XXX', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)

-新式类:

  1.凡是继承object的类或子孙类都是新式类。

  2.在python3中所有的类都默认继承object。

-经典类:

  1.在python2中才会有经典类与新式类之分。

  2.在python2中,凡是没有继承object的类,都是经典类。

class User(object):
    pass

class User:  # (<class 'object'>,)
    x = 10
    pass


class Sub(User):
    pass


print(User.__dict__)

print(object)

钻石继承(菱形继承)

多继承情况下造成“钻石继承”

  mro的查找顺序:

    -新式类

      -广度优先

    -经典式

      -深度优先

class A(object):
    # def test(self):
    #     print('from A')
    pass

class B(A):
    # def test(self):
    #     print('from B')
    pass

class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass

class E(C):
    # def test(self):
    #     print('from E')
    pass

class F(D, E):
    # def test(self):
    #     print('from F')
    pass

# F-->D-->B-->E-->C-->A-->object
# print(F.mro())
obj = F()
obj.test()

 

 

原文地址:https://www.cnblogs.com/lvguchujiu/p/11937787.html