Python面向对象 | 抽象类和接口类
一、抽象类(规范的编程模式)
什么是抽象类
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。抽象类的本质还是类,指的是一组类的相似性,而接口只强调函数属性的相似性。
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
抽象类是介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
抽象类就是制定一个规则,让其他人按照我的规则写程序。 约定俗称规范,但是有人不按照这个执行。
归一化设计 强制指定规范.
写一个抽象类:
- from abc import ABCMeta,abstractmethod
- 需要用到abc模块,在这个类创建的时候指定 metaclass = ABCMeta
- 在你希望子类实现的方法上加上 @abstramethod 装饰器
举例,支付宝和qq支付,统一支付方式:实例化的时候,有不规范的,直接报错呢
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
"""
此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
"""
@abstractmethod
def pay(self):
pass
class Alipay(Payment):
def pay(self,money):
print('使用支付宝支付了%s元' % money)
class Wechatpay(Payment):
def pay(self,money):
print('使用微信支付了%s元' % money)
class ApplePay(Payment):
def pay(self,money):
print('使用applepay支付了%s元' % money)
def pay(object,money): # 归一化设计
object.pay(money) # 执行实例化对象的类方法
# p = Payment() #抽象类不能实例化,TypeError: Can't instantiate abstract class Payment with abstract methods pay
a = Alipay()
a.pay(100)
pay(a,100) # 上下效果相同
# Payment不需要pay的代码,只需要子类实现即可
# Payment没有任何代码实现,必须要求子类有同名的方法名
'''
执行输出:
使用支付宝支付了100元
使用支付宝支付了100元
'''
这个统一的方法,叫做归一化设计
归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
抽象类和接口类做的事情 :建立规范
制定一个类的metaclass是ABCMeta,那么这个类就变成了一个抽象类(接口类),这个类的主要功能就是建立一个规范
抽象类中所有被abstractmethod装饰的方法都必须被继承的子类实现。如果不实现,那么在实例化阶段将会报错
无论是抽象类还是接口类metaclass=ABCMeta 都不可以被实例化。p = Payment() 报错
如果抽象类没有abstractmethod装饰器,那么这个方法,子类不需要实现。把fuqian改成pay就可以实例化了
二、接口类
接口类:定义一个接口对继承类进行约束,接口里有什么方法,继承类就必须有什么方法,接口中不能有任何功能代码
比如动物园里面的动物,会游泳,走路,爬树,飞行的动物。定义几个动物:
class Tiger(object): # 老虎
def walk(self):pass # 走路
def swim(self):pass # 游泳
class Monkey(object): # 猴子
def walk(self):pass
def climb(self):pass # 爬树
class Swan(object): # 天鹅
def walk(self): pass
def swim(self): pass
def fly(self):pass # 飞行
def cal_flying_speed(self):pass # 计算飞行速度
def cal_flying_height(self):pass # 计算飞行高度
观察上面的代码,技能重复了。这样写,容易丢失方法。加一个鹦鹉,但是它少了一些飞行类的方法
class Parrot(object):
def fly(self):pass
def cal_flying_speed(self): pass
怎么解决这个问题呢?定义一个抽象类A
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
@abstractmethod
def fly(self): pass
@abstractmethod
def cal_flying_speed(self): pass
@abstractmethod
def cal_flying_height(self): pass
class Tiger(object): # 老虎
def walk(self): pass # 走路
def swim(self): pass # 游泳
class Monkey(object): # 猴子
def walk(self): pass
class Swan(A): # 天鹅
def walk(self): pass
def swim(self): pass
def fly(self): pass # 飞行
def cal_flying_speed(self): pass # 计算飞行速度
def cal_flying_height(self): pass # 计算飞行高度
class Parrot(A):
def fly(self): pass
def cal_flying_speed(self): pass
Swan() # 没问题
Parrot() # 报错
'''
执行报错:
TypeError: Can't instantiate abstract class Parrot with abstract methods cal_flying_height
'''
鹦鹉实例化时,报错,找不到方法cal_flying_height。这样就约束了飞行动物的方法。所有会走的动物,具有一些会走的动物特性。对于爬行动物,不能继承A,所以需要再定义一抽象类
from abc import ABCMeta,abstractmethod
class FlyAnimal(metaclass=ABCMeta): # 飞行
@abstractmethod
def fly(self):pass # 接口中的方法函数不能有任何内容
@abstractmethod
def cal_flying_speed(self):pass
@abstractmethod
def cal_flying_height(self):pass
class WalkAnimal(metaclass=ABCMeta): # 走路
@abstractmethod
def walk(self):pass
class SwimAnimal(metaclass=ABCMeta): # 游泳
@abstractmethod
def swim(self):pass
class Tiger(WalkAnimal,SwimAnimal): # 老虎,继承走路和游泳
def walk(self):pass # 走路
def swim(self):pass # 游泳
class Monkey(WalkAnimal): # 猴子
def walk(self):pass
def climb(self):pass # 爬树
class Swan(FlyAnimal,WalkAnimal,SwimAnimal): # 天鹅,继承飞行,走路,游泳
def walk(self): pass
def swim(self): pass
def fly(self):pass # 飞行 #调用时,要完成代码
def cal_flying_speed(self):pass # 计算飞行速度
def cal_flying_height(self):pass # 计算飞行高度
class Parrot(FlyAnimal): # 鹦鹉,继承飞行
def fly(self):pass
def cal_flying_speed(self): pass
def cal_flying_height(self): pass
#实例化
Tiger()
Monkey()
Swan()
Parrot()
执行输出,就没有报错了。
接口隔离原则:
使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。
不能使用单一的总接口来完成,所以需要定义多个抽象类,同时,不需要的接口不要给底层类继承。
抽象类和接口类总结:
在python中,并没有什么不同,都是用来约束子类中的方法的;
只要是抽象类和接口类中被abstractmethod装饰的方法,都需要被子类实现;
当多个类有相同的功能也有不同的功能的时候,应该采用多个接口类来进行分别的约束
面试的时候,可能会问:什么是抽象类?什么是接口类?
抽象类 是python中定义类的一种规范,用来约束子类中的方法的。被abstractmethod装饰的方法,子类必须实现,否则实例化时报错。
接口类 满足接口隔离原则,且完成多继承的约束。如果不按照规范,在调用方法时,报错。
Python面向对象 | 抽象类和接口类的更多相关文章
- python基础 抽象类(接口类)
Python中没有接口.接口类,抽象类:定义 制定一个规范 #必须要导入from abc import ABCMeta,abstractmethod class Payment(metaclass = ...
- python开发面向对象基础:接口类&抽象类&多态&钻石继承
一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实 ...
- python之路----继承的抽象类和接口类
抽象类与接口类 接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数 ...
- Python抽象类和接口类
一.抽象类和接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名) ...
- python's twenty-first day for me 抽象类和接口类以及多态
归一化设计: 不管是哪一个类的对象,都调用同一个函数去完成相似的功能. class Alipay: def pay(self,money): print('使用支付宝支付了%s' % money) c ...
- 抽象类,接口类,封装,property,classmetod,statimethod
抽象类,接口类,封装,property,classmetod,statimethod(类方法,静态方法) 一丶抽象类和接口类 接口类(不崇尚用) 接口类:是规范子类的一个模板,只要接口类中定义的,就应 ...
- php 抽象类和接口类
PHP中抽象类和接口类都是特殊类,通常配合面向对象的多态性一起使用. 相同: ①两者都是抽象类,都不能实例化. ②只有接口类的实现类和抽象类的子类实现了 已经声明的 抽象方法才能被实例化. 不同: ① ...
- python 使用abc实现接口类/虚类(2.2)
python 使用abc实现接口类/虚类 具体类 class BaseA: def run(self): print('base A running') class ChildA(BaseA): de ...
- python面向对象 : 抽象类(接口类),多态,封装(私有制封装)
一. 抽象类(接口类) 与java一样, python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类, 它的特殊之处在于只能被继承, 不能被实例化. 从设计角度去看, 如果类是从现实对 ...
随机推荐
- 从头学一次J2EE笔记
1.在Servlet3.5规范之前,Java Web 应用的绝大部分组件都通过web.xml 文件来配置管理, Servlet3.0 规范可通过Annotation来配置管理Web组件,因此web.x ...
- 【07月16日】A股滚动市净率PB历史新低排名
2010年01月01日 到 2019年07月16日 之间,滚动市净率历史新低排名. 上市三年以上的公司,2019年07月16日市净率在30以下的公司. 来源:A股滚动市净率(PB)历史新低排名. 1 ...
- 使用velero进行kubernetes灾备
使用velero可以对集群进行备份和恢复,降低集群DR造成的影响.velero的基本原理就是将集群的数据备份到对象存储中,在恢复的时候将数据从对象存储中拉取下来.可以从官方文档查看可接收的对象存储,本 ...
- HTML+css基础 p段落标签 a 超链接标签 Src和href有什么区别和关联? target属性 Meta标签
p段落标签: <p></p> 1.他是唯一一个可以不写结束标签的双标签. a 超链接标签: 从一个页面链接到另一个页面.靠的是href属性. Src和href有什么区别和关联 ...
- ReentrantReadWriteLock 源码分析
ReentrantReadWriteLock 源码分析: 1:数据结构: 成员变量: private final ReentrantReadWriteLock.ReadLock readerLock ...
- Deep Learning专栏--强化学习之MDP、Bellman方程(1)
本文主要介绍强化学习的一些基本概念:包括MDP.Bellman方程等, 并且讲述了如何从 MDP 过渡到 Reinforcement Learning. 1. 强化学习基本概念 这里还是放上David ...
- golang 学习笔记 ---JSON
JSON解析到结构体 在介绍这部分之前先简要介绍一下Json语法 JSON 语法是 JavaScript 语法的子集.JSON 语法是 JavaScript 对象表示法语法的子集. 数据在名称/值对中 ...
- 【05】C#特有的ref、out参数
java和C#非常相似,它们大部分的语法是一样的,但尽管如此,也有一些地方是不同的. 为了更好地学习java或C#,有必要分清它们两者到底在哪里不同. 我们这次要来探讨C#特有的ref.out参数. ...
- Natasha V1.3.6.0 的升级日志
开源库满足于个人,而完善于大众. Natasha 自稳定版发布之后,众多老铁参与增强改进,感谢如下老铁的反馈: 1. 异常搜集 在 wenjq0911 建议下,添加了异常捕获,现 Natasha 的编 ...
- Go是如何生活在内存条里的【译】
原文:A visual guide to Go Memory Allocator from scratch (Golang) 当我第一次开始试图了解 Go 的内存分配器时,觉得它真令人抓狂.所有的所有 ...