29、继承

一、继承

1.1、什么是继承

  继承是一种创建新类的方式,新建的类可以称为子类或者派生类,父类可以称为基类或者超类,子类会遗传父类
1.2、Python中的继承

  python中支持多继承关系,一个子类可以继承一个或者多个父类

class Parent1object):
    x=1111
class Parent2object):
    pass
class Sub1Parent1):                                        # 单继承
    pass
class Sub2Parent1,Parent2):                            # 多继承
    pass
printSub1.__bases__)
printSub2.__bases__)
printSub1.x)

1.3、python2以及python3中继承的区别

  python2

    新类式:继承可了object类的子类

    经典式:没有继承object类的子类

  python3

    python3中只有新类式,没有继承任何类的都会默认继承object类
1.4、python的多继承

  优点:

    子类可以继承多个父类,最大程度的限制重用代码
  缺点:

    1、违背人的思维习惯,继承表达的是一种什么是什么的关系

    2、代码可读性变差

    3、不建议使用多继承,有肯能会引发菱形问题,扩展性变差
  注:

    如果不可避免的需要使用到多个父类的属性,应该使用mixins

1.5、为什么要使用继承

  解决类与类之间的代码冗余问题

1.6、怎么实现继承

  当子类需要的代码都在父类中时,可以直接引用

  当子类需要的代码只有部分在父类时,编写类,再指名道姓的从父类中引用代码例如:

  def __init__self, name, age, sex, salary, level):               类

  OldboyPeople.__init__self,name,age, sex)                    

class OldboyPeople:                                    #通用的父类代码
    school = 'OLDBOY'
    def __init__self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class StudentOldboyPeople):                       #子类代码和父类代码一致,直接从父类代码中引用
    def choose_courseself):
        print'学生%s 正在选课' % self.name)
stu_obj = Student'lili', 18, 'female')
stu_obj.choose_course)

class TeacherOldboyPeople):                      #子类代码中只有部分功能在父类中     老师的空对象,'egon',18,'male',3000,10    类中的数据要写全
    def __init__self, name, age, sex, salary, level):                
    
# 指名道姓地跟父类OldboyPeople去要__init__ OldboyPeople.__init__self,name,age, sex) self.salary = salary self.level = level def scoreself): print'老师 %s 正在给学生打分' % self.name) tea_obj=Teacher'egon',18,'male',3000,10) tea_obj.score)

二、继承属性的查找

2.1、有了继承关系之后,对象在查找属性时,会先从自身__dict__里面找,如果没有回去子类中查找,最后到父类中

  例题一:子类中没有找到,在父类中找到,父类的函数下子类和父类中都有,会直接先从子类中读取  

class Foo:
    def f1self):
        print'Foo.f1')

    def f2self):
        print'Foo.f2')
        self.f1) # obj.f1)

class BarFoo):
    def f1self):
        print'Bar.f1')

obj=Bar)
obj.f2)                           #Foo.f2    Foo.f1

3.2、子类中找不到的情况下,在父类中找到了,接着父类的函数会直接指向子类,如果要强行指向父类中,需要指明道姓的调用父类函数:Foo.f1self)

class Foo:
    def f1self):
        print'Foo.f1')

    def f2self):
        print'Foo.f2')
        Foo.f1self) # 调用当前类中的f1

class BarFoo):
    def f1self):
        print'Bar.f1')

obj=Bar)
obj.f2)

# Foo.f2
# Foo.f1

3.3、从父类调用时,遇到隐藏属性的类,名字将会变形,但是对外不对内,所以自找到父类中的函数

class Foo:
    def __f1self): # _Foo__f1
        print'Foo.f1')

    def f2self):
        print'Foo.f2')
        self.__f1) # self._Foo__f1,# 调用当前类中的f1

class BarFoo):
    def __f1self): # _Bar__f1
        print'Bar.f1')

obj=Bar)
obj.f2)

# Foo.f2
# Foo.f1

四、多继承关系带来的菱形问题

4.1、菱形问题以及MRO的介绍

  菱形问题指的是有多个父类,父类最终又指向同一个父类

  MRO:指的是类的对象访问属性的查找顺序是根据MRO的显示

4.2、查找顺序

  非菱形:

    按照子类的父类从左到右的顺序,一个分支一个分支的找下去,

  菱形:

    经典型:深度优先,每一个分支找到底,直到最终的父类,第二个分支将不会找最终的父类

    新类型:广度优先,最后一个分支才会找到最终的父类,其余的父类都会直接跳过

class G: # 在python2中,未继承object的类及其子类,都是经典类
# def testself):
# print'from G')
pass

class EG):
# def testself):
# print'from E')
pass

class FG):
def testself):
print'from F')

class BE):
# def testself):
# print'from B')
pass

class CF):
def testself):
print'from C')

class DG):
def testself):
print'from D')

class AB,C,D):
# def testself):
# print'from A')
pass

# 新式类
# printA.mro)) # A->B->E->C->F->D->G->object

# 经典类:A->B->E->G->C->F->D
obj = A)
obj.test) #

4.3、总结

  多继承要不要用?

  要用,但是需要规避几个问题

  1.继承结构不要过于复杂

  2.推荐使用mixins机制,在多继承的背景下满足什么是什么的关系

5、mixins机制

  多继承的正确打开方式:mixins

  mixins的核心:在多继承的背景下,尽可能的提升多继承的可读性,也就是让多继承满足人的思维方式===》什么是什么

  汽车和飞机都属于交通工具,其中两种飞机有属于能飞的,所以父类的条件是交通工具和能飞,将能飞这个条件提取出来,单独放在左边,因为新类型最后再回找最终的父类。

class Vehicle:
    pass

class FlyableMixin:
    def flyself):
        pass

class CivilAircraftFlyableMixin,Vehicle):  # 民航飞机
    pass

class HelicopterFlyableMixin,Vehicle):  # 直升飞机
    pass

class CarVehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
    pass


import socketserver
# 补充:通常Mixin结果的类放在左边

 六、子类中如何应用父类的功能

  使用super()调用父类提供给自己的方法====》严格依赖继承关系

  调用super()会得到一个特殊的对象,该对象会参考发起属性查找那个类MRO,去当前父类中查找属性(mro中的属性)

class OldboyPeople:
    def __init__self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def f1self):
        print'%s say hello' %self.name)


class TeacherOldboyPeople):
    def __init__self,name,age,sex,level,salary):
        # superTeacher,self).__init__name,age,sex)
        super).__init__name,age,sex) # 调用的是方法,自动传入对象

        self.level = level
        self.salary=salary

# printTeacher.mro))
tea_obj=Teacher'egon',18,'male',10,3000)
printtea_obj.__dict__)

  

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注