zoukankan      html  css  js  c++  java
  • Python开发基础-Day18继承派生、组合、接口和抽象类

    类的继承与派生

    经典类和新式类

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

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

    1 class People:
    2     pass
    3 class Animal:
    4     pass
    5 class Student(People,Animal): #People、Animal称为基类或父类,Student为子类,Student继承了People和Animal的所有属性
    6     pass
    7 print(Student.__bases__)    #__bases__方法,查看继承的类的元组
    8 print(People.__bases__)
    9 print(Animal.__bases__)

    输出结果:

    1 (<class '__main__.People'>, <class '__main__.Animal'>)    #继承了两个父类
    2 (<class 'object'>,)    #默认继承了object类
    3 (<class 'object'>,)

    继承

    继承是为了减少代码重用的问题,以减少代码冗余。

    继承是一种是什么是什么的关系,例如老师类是人类,而非老师类是生日类

    继承类示例:

     1 class People:    #定义父类People
     2     def __init__(self, name, age):
     3         self.name = name
     4         self.age = age
     5     def walk(self):
     6         print('%s is walking' %self.name)
     7 
     8 #Teacher类和Student类无任何属性
     9 class Teacher(People):    #Teacher类继承People类的属性
    10     pass
    11 class Student(People):    #Student类继承People类的属性
    12     pass

    引用测试:

     1 t=Teacher('bob',18)    #实例化一个Teacher对象,而非People对象,Student子类同理
     2 print(type(t)) 
     3 print(t.name,t.age)
     4 print(t.__dict__)
     5 t.walk()    #Teacher子类继承了People的属性,使得Teacher子类的对象能够调用到父类的属性
     6 
     7 输出结果:
     8 <class '__main__.Teacher'>
     9 bob 18
    10 {'name': 'bob', 'age': 18}
    11 bob is walking

    派生

    派生是在子类继承父类的基础上, 定义子类独有的属性,例如Teacher可以有教师等级的划分、有教学课程的划分,但是继承父类People类是没有等级和课程的划分的。

    示例:

     1 #定义父类People
     2 class People:
     3     def __init__(self, name, age,sex):
     4         self.name = name
     5         self.age = age
     6         self.sex=sex
     7     def walk(self):
     8         print('%s is walking' % self.name)
     9     def test(self):
    10         print('test class from father class %s' %self.name)
    11 #定义Teacher子类
    12 class Teacher(People):
    13     school = 'jialidun'
    14     def __init__(self, name, age,sex,level,salary):
    15         People.__init__(self,name,age,sex)    #继承父类的初始化内容,实例化时候接收的参数name、age、sex会传给People.__init__
    16         self.level=level    #派生的独有属性
    17         self.salary=salary    #派生的独有属性
    18     def teach(self):    #派生的独有属性
    19         print('%s is teaching' %self.name)
    20     def test(self):    #派生父类的已有属性,对象在进行属性引用的时候会优先引用实例化过程中用到的类
    21         People.test(self)
    22         print('from teacher')
    23 #定义Student子类
    24 class Student(People):
    25     def __init__(self, name, age,sex,group):
    26         People.__init__(self, name, age, sex)
    27         self.group=group
    28     def study(self):
    29             print('%s is studying' %self.name)

    测试验证:

    1 t=Teacher('natasha',18,'male',10,3000) #__init__(t,'natasha',18,'male',10,3000)
    2 print(Teacher.__bases__)
    3 print(Teacher.__dict__)
    4 t.test()

    组合

    不同于继承,组合是包含的意思,表示一种什么有什么的关系,也是为了减少重复代码的

    示例:还是People、Teacher和Student的例子,只是加上了一个Birthday生日类

     1 #Birthday类,需要传入年月日
     2 class Birthday:
     3     def __init__(self,year,mon,day):
     4         self.year=year
     5         self.mon=mon
     6         self.day=day
     7     def tell_birth(self):
     8         print('出生于<%s>年 <%s>月 <%s>日' % (self.year,self.mon,self.day))
     9 #People类,需要接受名字年龄年月日,年月日传给Birthday类
    10 class People:
    11     def __init__(self, name, age, year, mon, day):
    12         self.name = name
    13         self.age = age
    14         #__init__接收的year, mon, day传给Birthday类
    15         self.birth = Birthday(year, mon, day)   #包含Birthday类,生日不只是人类才有,其他动物也可以有生日,不同于继承
    16     def walk(self):
    17         print('%s is walking' % self.name)
    18 #Teacher类
    19 class Teacher(People):
    20     def __init__(self, name, age, year, mon, day,level,salary):
    21         #__init__接收的name, age, year, mon, day传给People类
    22         People.__init__(self,name,age,year,mon,day)
    23         self.level=level
    24         self.salary=salary
    25     def teach(self):
    26         print('%s is teaching' %self.name)
    27 #Student类
    28 class Student(People):
    29     def __init__(self, name, age, year, mon, day,group):
    30         People.__init__(self,name,age,year,mon,day)
    31         self.group=group
    32     def study(self):
    33         print('%s is studying' %self.name)

    测试验证:

    1 t=Teacher('hurry',18,1990,2,33,10,3000)    #传入的值为Teacher类接收的值
    2 print(t.name,t.age)    #对象t的名字和年龄
    3 print(t.birth)    #输出的是一个类对象,因为父类People定义的birth属性就是一个类Birthday
    4 t.birth.tell_birth()    #查看对象t所继承的People类的birth属性(Birthday类)的tell_birth()属性
    5 print(t.birth.year)
    6 print(t.birth.mon)
    7 print(t.birth.day)

    接口和抽象类

    接口

    接口是一组功能的入口,要调用某一组功能,需要通过接口来进行调用,而不需要关注这组功能是如何实现的,要的只是结果。

    在类里,接口是提取了一群类共同的函数,可以把接口当做一个函数的集合。

    python模仿接口示例:

     1 #模仿Linux内文件读写的接口,Linux不管是文本,还是磁盘还是进程都是通过文件去实现的,只不过方法不同,但是没关系
     2 class File:    #定义一个接口类,提供read和write方法,但是一定是pass没有处理过程的,因为功能的实现具体靠的是子类
     3     def read(self): #定接口函数read
     4         pass
     5     def write(self): #定义接口函数write
     6         pass
     7 #定义子类实现读写功能
     8 #文本文件的读写
     9 class Txt(File): #文本,具体实现read和write
    10     def du(self):     #注意并不是read
    11         print('文本数据的读取方法')
    12     def xie(self):    #注意并不是write
    13         print('文本数据的写入方法')
    14 #硬盘数据的读写
    15 class Sata(File): #磁盘,具体实现read和write
    16     def read(self):
    17         print('硬盘数据的读取方法')
    18     def write(self):
    19         print('硬盘数据的写入方法')
    20 #进程数据的读写
    21 class Process(File):
    22     def read(self):
    23         print('进程数据的读取方法')
    24     def write(self):
    25         print('进程数据的写入方法')

    测试验证:硬盘和进程一样,所以制作文本和硬盘的测试即可

    硬盘读写测试:

    1 disk=Sata()    #实例化一个硬盘读写对象
    2 disk.read()    #硬盘读
    3 disk.write()    #硬盘写
    4 
    5 输出结果:
    6 硬盘数据的读取方法
    7 硬盘数据的写入方法

    文本读写测试:执行后会发现没有任何输出,那是因为txt对象实际上访问的read和write属性并非子类Txt所提供的属性,Txt所提供的属性只是du和xie,但是txt对象有read和write属性,别忘了Txt类是继承了父类File的属性,所以实际上txt对象的read和write属性是父类File提供的

    1 txt=Txt()
    2 txt.read()
    3 txt.write()

    正确的做法是将Txt类的du和xie方法改成read和write方法,这么做的意义为归一化

    归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。

    抽象类

    抽象类的本质上也是类,但是抽象类只能够被继承,不能进行实例化,也就是说可以当父类,但是不能生成对象。

    抽象类介于接口和归一化中间,用于实现接口的归一化

    当子类继承抽象类的时候,如果抽象类定义了抽象方法,那么子类必须要定义同名的方法。即父类限制:

      1、子类必须要有父类的方法

      2、子类实现的方法必须跟父类的方法的名字一样

    python的抽象类通过abc模块实现。

    接口归一化示例:

     1 import abc
     2 class File(metaclass=abc.ABCMeta):  #metaclass指的是元类,边会讲,现在只需记住这个词
     3     @abc.abstractmethod     #抽象方法,即一个装饰器装饰read属性
     4     def read(self):
     5         pass
     6     @abc.abstractmethod      #抽象方法,即一个装饰器装饰write属性
     7     def write(self):
     8         pass
     9 # # 当继承File类时候,如果没有read和write方法,会提示出错TypeError: Can't instantiate abstract class Txt with abstract methods read, write
    10 # class Txt(File):
    11 #     def du(self):
    12 #         print('文本数据的读取方法')
    13 #     def xie(self):
    14 #         print('文本数据的写入方法')
    15 #定义子类具体实现文本的读写操作
    16 class Txt(File):
    17     def read(self):
    18         print('文本数据的读取方法')
    19     def write(self):
    20         print('文本数据的写入方法')
    21 #定义子类具体实现硬盘的读写操作
    22 class Sata(File):
    23     def read(self):
    24         print('硬盘数据的读取方法')
    25     def write(self):
    26         print('硬盘数据的写入方法')
    27 #定义子类具体实现进程的读写操作
    28 class Process(File):
    29     def read(self):
    30         print('进程数据的读取方法')
    31     def write(self):
    32         print('进程数据的写入方法')

    测试验证:

     1 t=Txt()
     2 t.read()
     3 t.write()
     4 s=Sata()
     5 s.read()
     6 s.write()
     7 输出结果:
     8 文本数据的读取方法
     9 文本数据的写入方法
    10 硬盘数据的读取方法
    11 硬盘数据的写入方法
  • 相关阅读:
    MySQL学习笔记
    为什么使用多态?实现多态的有哪些方式
    C++中派生类使用基类成员的问题
    实现Modbus ASCII多主站应用
    PHP第四天 函数引用传值
    Webpack 快速上手(下)
    Java---23种设计模式(九)------组合模式
    【笔记】Linux就该这么学-第六课第四章
    Node.js HTTPS
    Node.js Smalloc
  • 原文地址:https://www.cnblogs.com/zero527/p/7112757.html
Copyright © 2011-2022 走看看