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 硬盘数据的写入方法
时间: 2024-08-26 07:53:15

Python开发基础-Day18继承派生、组合、接口和抽象类的相关文章

python基础之继承派生、组合、接口和抽象类

类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承object类的子类成为经典类(在python2中,没有继承object的类,以及它的子类,都是经典类) 1 class People: 2 pass 3 class Animal: 4 pass 5 class Student(People,Animal): #People.Animal称为基类或父类,

Python 继承和组合 接口

#解决代码重用的问题,减少代码冗余 #继承是一种什么'是'什么的关系 class People: def __init__(self, name, age): # print('People.__init__') self.name = name self.age = age def walk(self): print('%s is walking' %self.name) class Teacher(People): pass class Student(People): pass # t=T

慢慢人生路,学点Jakarta基础-深入剖析Java的接口和抽象类

在java面向对象编程的,抽象类和接口始终存在有疑问的地方,因为两者太多相似有太多不同,在刚开始学习的时候经常弄的不对,使用情景搞混,今天来总结之前学习Java中接口和抽象类的问题. 抽象类 了解:只声明,未具体实现. abstract void cry(); 抽象方法必须使用关键字abstract进行修饰,如果一旦一个类中包含了abstract方法,那么这个类必须使用abstract进行修饰:因为抽象类中含有未实现的方法,抽象类不能被实例化:抽象类不一定包含抽象方法,也就是说抽象类可以没有抽象

Python开发基础-Day23try异常处理、socket套接字基础1

异常处理 错误 程序里的错误一般分为两种: 1.语法错误,这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正 2.逻辑错误,人为造成的错误,如数据类型错误.调用方法错误等,这些解释器是不会进行检测的,只有在执行的过程中才能抛出的错误 异常 异常是python解释器在运行程序的过程中遇到错误所抛出的信息,如: Python异常种类: 常用异常: 1 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x 2 IOError 输入/输出异

Python开发基础----异常处理、socket套接字基础1

异常处理 错误 程序里的错误一般分为两种: 1.语法错误,这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正 2.逻辑错误,人为造成的错误,如数据类型错误.调用方法错误等,这些解释器是不会进行检测的,只有在执行的过程中才能抛出的错误 异常 异常是python解释器在运行程序的过程中遇到错误所抛出的信息,如: Python异常种类: 常用异常: 1 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x 2 IOError 输入/输出异

python开发基础篇(一)

变量及其定义规范 1 #变量名(相当于门牌号,指向值所在的空间),等号,变量值 2 name='Egon' 3 sex='male' 4 age=18 5 level=10 变量的定义规范 #1. 变量名只能是 字母.数字或下划线的任意组合 #2. 变量名的第一个字符不能是数字 #3. 关键字不能声明为变量名['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', '

Python开发基础-Day22反射、面向对象进阶

isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象,如果是返回True 1 class Foo(object): 2 pass 3 obj = Foo() 4 print(isinstance(obj, Foo)) issubclass(sub, super)检查sub类是否是 super 类的派生类,如果是返回True 1 class Foo(object): 2 pass 3 cla

Python开发基础--- 进程间通信、进程池、协程

进程间通信 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 进程队列queue 不同于线程queue,进程queue的生成是用multiprocessing模块生成的. 在生成子进程的时候,会将代码拷贝到子进程中执行一遍,及子进程拥有和主进程内容一样的不同的名称空间. 示例1: 1 import multiprocessing 2 def foo(): 3 q.put([11,'hello',True]

Python开发基础--- Event对象、队列和多进程基础

Event对象 用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象 event对象默认为假(Flase),即遇到event对象在等待就阻塞线程的执行. 示例1:主线程和子线程间通信,代码模拟连接服务器 1 import threading 2 import time 3 event=threading.Event() 4 5 def foo(): 6 print('wait server...') 7 event.wait() #括号里可