- 继承有两种用途:
- 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
- 二:实现接口类
- 什么是接口类?
- 接口类实际上就是一个规范子类的类,只不过这个类与别的类不太一样,接口类内部的方法本身不实现,子类继承接口类,子类需要实现接口的功能,否则无法正常工作。
- 作用:就是规范好子类的接口(项目经理必用)。
- 思考:在公司开发的时候,首先第一步就是需要将整个项目的业务进行梳理,比如需要有登录的功能,然后有注册和支付的功能and so on。那个整理这个业务逻辑的人,会制定一些规范,比如不同业务实现功能方法的名称,参数等等,便于让下面的开发人员按照严谨指定好的业务流程进行功能实现的程序开发。
- 在Python中定义一个接口类,我们需要abc模块(抽象类基类,Abstract Base Classes)中的两个工具abstractmethod, ABCMeta,详情如下:
| 工具 | 说明 |
|---|---|
| abstractmethod | 抽象类的装饰器,接口类中的接口需要使用此装饰器 |
| ABCMeta | 抽象类元类 |
- 什么是类的元类?
- 在Python3版本中,如果定义一个类,该类没有明确写出父类是谁,那么默认情况下,这个类的父类为object类,因此我们认为object类是所有自定义类的"元类"
- 简单来说就是object是用来创建类的,就好比类是用来创建对象的。如果说类是对象的模板,那么object就是类的模板。
- 除此之外,可以使用metaclass来制定一个类的"元类"
- 在Python3版本中,如果定义一个类,该类没有明确写出父类是谁,那么默认情况下,这个类的父类为object类,因此我们认为object类是所有自定义类的"元类"
- 图形的接口类示例
接下来我们来定义一个图形的接口类GraphicRule和子类Rectangle,提供两个接口,如下:
| 接口 | 说明 |
|---|---|
| area | 图形的面积 |
| perimeter | 图形的周长 |
接口类仅提供接口的约束,不实现其接口功能,由其子类的矩形类Rectangle实现,如果子类Rectangle不实现接口类GraphicRule中所有的接口,即area和perimeter,在实例对象的时候,会抛出异常
from abc import ABCMeta,abstractmethod #从abc模块中导入ABCMeta这个元类
class GraphicRule(metaclass=ABCMeta): #接口类:
@abstractmethod
def area(self,length,width):
pass
@abstractmethod
def perimeter(self,length,width):
pass
class Rectangle(GraphicRule): #子类继承了接口类后,才可以实现接口类中指定好的规范
def __init__(self,length,width):
self.length = length
self.width = width
#对父类这个接口类中指定好的规范进行实现
def area(self,length,width):
return length * width
def perimeter(self,length,width):
return (length+width)*2
r = Rectangle(2,3)
r.area(2,3)
from abc import ABCMeta,abstractmethod #从abc模块中导入ABCMeta这个元类
class GraphicRule(metaclass=ABCMeta): #接口类:
@abstractmethod
def area(self,length,width):
pass
@abstractmethod
def perimeter(self,length,width):
pass
class Rectangle(GraphicRule): #子类继承了接口类后,才可以实现接口类中指定好的规范
def __init__(self,length,width):
self.length = length
self.width = width
#对父类这个接口类中指定好的规范进行实现
def area(self,length,width):
return length * width
def perimeter(self,length,width):
return (length+width)*2
r = Rectangle(2,3)
r.area(2,3)
抽象类
- 什么是抽象类
- 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。
- 为什么要有抽象类?
- 如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
- 比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
- 从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
- 从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的
from abc import abstractmethod, ABCMeta
class Fruit(metaclass=ABCMeta):
@abstractmethod
def func1(self):
pass
@abstractmethod
def func2(self):
pass
#可以定义正常方法
def normalFunc(self):
print('i am nomal func!')
class Apple(Fruit):
def func1(self):
print('i am func1')
def func2(self):
print('i am func2')
Apple().normalFunc()
- 抽象类和接口类的同异
- 相同:
- 都有抽象方法
- 都不可以实例化
- 不同:
- 抽象类:约束子类中必须包含某些方法 // 弱约束
- 接口类:约束子类中必须包含父类规定的方法 // 强约束
- 相同:
先看下面的代码:
pass
狗、猫、猪都继承了动物类,并各自重写了kind方法。show_kind()函数接收一个animal参数,并调用它的kind方法。可以看出,无论我们给animal传递的是狗、猫还是猪,都能正确的调用相应的方法,打印对应的信息。这就是多态。
实际上,由于Python的动态语言特性,传递给函数show_kind()的参数animal可以是 任何的类型,只要它有一个kind()的方法即可。动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。



