zoukankan      html  css  js  c++  java
  • 面向对象(二)——继承、派生、组合以及接口

    一、继承与派生

    1.1 什么是继承

    继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

    Python中类的继承分为:单继承和多继承

    class People:    # 定义父类
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def walk(self):
                print('%s is walking' %self)
    class Teacher(People):    # 单继承,基类是People,派生类是Teacher
        pass
    class Student(People):    #  单继承,基类是People,派生类是Student
        pass
    t=Teacher('egon',18)
    print(t.name,t.age)
    print(t.__dict__)
    t.walk()

    需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时为指定,Python从左至右搜索即方法在子类中未找到时,从左到右查找基类中是否包含方法。

    如果没有指定基类,Python的类会默认继承object类,object是所有Python类的基类,它提供了一些常见方法如(__str__)的实现

    BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:

    class DerivedClassName(modname.BaseClassName):
    

    单继承实例:

    #类定义
    class people:
        #定义基本属性
        name = ''
        age = 0
        #定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
        #定义构造方法
        def __init__(self,n,a,w):
            self.name = n
            self.age = a
            self.__weight = w
        def speak(self):
            print("%s 说: 我 %d 岁。" %(self.name,self.age))
    #单继承示例
    class student(people):
        grade = ''
        def __init__(self,n,a,w,g):
            #调用父类的
    View Code

    二、多继承

    class People:    # 定义父类
        pass
    class Animal:    # 定义父类
        pass
    class Student(People,Animal):    # 定义子类
        pass
    
    print(Student.__bases__)
    print(People.__bases__)
    print(Animal.__bases__)

    在Python3中,所有类默认继承object

    但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在Python3中所有的类都是新式类)

    没有继承object类的子类成为经典类(在Python2中,没有继承object的类,以及它的子类,都是经典类)

    继承的好处:

    解决代码重用的问题,减少代码冗余

    继承是一种什么‘是’什么的关系    # 比如:人是动物

    继承与派生
    class People:    # 定义父类
        # 定义构造方法
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def walk(self):
            print('%s is walking' %self.name)
        def foo(self):
            print('from father %s' %self.name)
    
    class Teacher(People):    # 定义派生(子类)
        school='oldboy'    # 定义基本属性
        def __init__(self,name,age,sex,level,salary):    # 定义构造方法
            People.__init__(self,name,age,sex)
            self.level=level
            self.salary=salary
        def teach(self):
            print('% is teaching' %self.name)
        def foo(self):
            People.foo(self)
            print('from teacher')
    
    class Student(People):    # 定义派生(子类)
        def __init__(self,name,age,sex,group):    # 定义构造方法
            People.__init__(self,name,age,sex)    # 调用父类的构函
            self.group=group
        def study(self):
            print('% is studying %self.name')
    
    t=Teacher('egon',18,'male',10,10000)    # 实例化对象
    s=Student('wocao',22,'male',12)    # 实例化对象
    print(t.__dict__)
    print(s.__dict__)
    t.foo()
    View Code
    三、组合
    软件重用的重要方式除了继承之外还有另外一种方式,即:组合
    组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
    class Date:
        def __init__(self,year,mon,day):
            self.year=year
            self.mon=mon
            self.day=day
        def tell_brith(self):
            print('出生于<%s>年 <%s>月 <%s>日' %(self.year,self.mon,self.day))
    
    class Teacher:
        def __init__(self,name,age,year,mon,day):
            self.name=name
            self.age=age
            self.brith=Date(year,mon,day)
        def teach(self):
            print('%s is teaching' %self.name)
    
    class Stdent:
        def __init__(self,name,age,year,mon,day):
            self.name=name
            self.age=age
            self.brith=Date(year,mon,day)
        def study(self):
            print('%s is studying' %self.name)
    
    t=Teacher('egon',18,1999,1,8)
    print(t.name,t.age)
    print(t.brith)
    print(t.brith.year)
    print(t.brith.mon)
    print(t.brith.day)
    t.brith.tell_brith()
    组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
       
    1.继承的方式

        通过继承建立了派生类与基类之间的关系,它是一种是的关系,比如白马是马,人是动物。

        当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师

    >>> class Teacher:
    ...     def __init__(self,name,gender):
    ...         self.name=name
    ...         self.gender=gender
    ...     def teach(self):
    ...         print('teaching')
    ...
    >>>
    >>> class Professor(Teacher):
    ...     pass
    ...
    >>> p1=Professor('egon','male')
    >>> p1.teach()
    teaching
    

      

    2.组合的方式
        用组合的方式建立了类与组合的类之间的关系,它是一种有的关系,比如教授有生日,教授教Python课程
    class BirthDate:
        def __init__(self,year,month,day):
            self.year=year
            self.month=month
            self.day=day
    
    class Couse:
        def __init__(self,name,price,period):
            self.name=name
            self.price=price
            self.period=period
    
    class Teacher:
        def __init__(self,name,gender):
            self.name=name
            self.gender=gender
        def teach(self):
            print('teaching')
    
    class Professor(Teacher):
        def __init__(self,name,gender,birth,course):
            Teacher.__init__(self,name,gender)
            self.birth=birth
            self.course=course
    
    p1=Professor('egon','male',
                 BirthDate('1995','1','27'),
                 Couse('python','28000','4 months'))
    print(p1.birth.year,p1.birth.month,p1.birth.day)
    print(p1.course.name,p1.course.price,p1.course.period)
    '''
    运行结果:
    1 27
    python 28000 4 months
    '''
    View Code
    当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
     
    四、接口与归一化设计
    1.什么是接口
    继承有两种用途:
    一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
    二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
    class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
        def read(self): #定接口函数read
            pass
        def write(self): #定义接口函数write
            pass
    class Txt(Interface): #文本,具体实现read和write
        def read(self):
            print('文本数据的读取方法')
        def write(self):
            print('文本数据的读取方法')
    class Sata(Interface): #磁盘,具体实现read和write
        def read(self):
            print('硬盘数据的读取方法')
        def write(self):
            print('硬盘数据的读取方法')
    class Process(Interface):
        def read(self):
            print('进程数据的读取方法')
        def write(self):
            print('进程数据的读取方法')
    继承的第二种含义非常重要,它又叫“接口继承”。
    接口继承实质上要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。
     
    五、抽象类
    1、什么是抽象类?
        抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
    2、为什么要有抽象类?
        如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
    3、在Python中实现抽象类
    # 父类要限制
    # 1 子类必须要有父类的方法
    # 2 子类实现的方法必须跟父类的方法的名字一样
    import abc    # 利用abc模块实现抽象类
    
    class File(metaclass=abc.ABCMeta):
        @abc.abstractmethod    # 定义抽象类方法,无需实现功能
        def read(self):
            ‘子类必须定义读功能’
            pass
        @abc.abstractmethod
        
        def writh(self):
            ‘子类必须定义写功能’
            pass
    
    class Txt(File):    # 子类继承抽象类,但是必须定义read和write方法
        def read(self):    # read方法,如果子类没有定义抽象方法,则报错
            pass
        def writh(self):    # write方法,和上面一样
            pass
    t=Txt()
    4、抽象类本质还是类,指的是一组类的相似性,包括数据属性和函数属性,而接口只强调函数属性的相似性。
    抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来现实归一化设计
     
    六、继承实现的原理(继承顺序)
    1 继承顺序
    class A(object):
        def test(self):
            print('from A')
    
    class B(A):
        def test(self):
            print('from B')
    
    class C(A):
        def test(self):
            print('from C')
    
    class D(B):
        def test(self):
            print('from D')
    
    class E(C):
        def test(self):
            print('from E')
    
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    f1=F()
    f1.test()
    print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    #新式类继承顺序:F->D->B->E->C->A
    #经典类继承顺序:F->D->B->A->E->C
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类
    继承顺序
    

      

    2、继承原理
    python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
    >>> F.mro() #等同于F.__mro__
    [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, 
    <class '__main__.A'>, <class 'object'>]
    mro只在新式类中有
     
    子类调用父类的方法
    super()函数,调用父类的绑定方法
    class People:
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
        def foo(self):
            print('from parent')
    
    class Teacher(People):
        def __init__(self,name,age,sex,salary,level):
            # People.__init__(self,name,age,sex)    # 指名道姓地调用People类的__init__函数
            
            # 在Python3中
            super().__init__(name,age,sex)  # 调用父类的__init__的功能,实际上用的是绑定方法,只能调用一次父类
          
            # 在Python2中
            # super(Teacher,self).__init__(name,age,sex)
            self.salary=salary
            self.level=level
        def foo(self):
            super().foo()
            print('from child')
    t=Teacher('egon',18,'male',3000,10)
    t.foo()
    View Code

    方法一:父类名.父类方法() 

    方法二:super() 

  • 相关阅读:
    TP5 关联模型使用(嵌套关联、动态排序以及隐藏字段)
    分布式与集群的区别是什么?
    模板函数函数模板 Function Template(C++Primer10)
    注意地方hadoop中的pi值计算
    文件错误关于hibernate中报Duplicate class/entity mapping org.model.User错的问题
    元素序列几个常用排序算法:一
    行语句mysql insert操作详解
    分量入度hdu 3836 Equivalent Sets
    查询语句编写高效SQL语句
    方法元素c语言范式编程之lsearch
  • 原文地址:https://www.cnblogs.com/shenbuer/p/7375641.html
Copyright © 2011-2022 走看看