Python抽象基类之声明协议
抽象基类之--声明协议
上回讲了Python中抽象基类的大概,相信大家对abcmeta以及什么是抽象基类已经有所了解。传送门
现在我们来讲讲抽象基类的另一个常用用法--声明协议
所谓声明协议,有点像Java中的接口这个概念。就是子类必须实现父类要求的方法。
1.不使用抽象基类来实现
1. 提出异常(规范起见请使用 NotImplementedError)
class Test(object):
def __init__(self):
self.salary = []
def work(self):
money = self._job()
self.salary.append(money)
return money
def _job(self):
raise NotImplementedError("Test子类必须实现 '_job' 方法")
如上所示的类,如果子类没有自己重写_job方法而执行work方法就会产生NotImplementedError异常,这样通过异常的方法就可以强迫子类必须实现父类规定的函数,但是这有个缺点:如果子类不调用work方法,那么子类就算没有实现_job方法也不会报错。
2. 使用元类
通过元类也可以实现声明协议的功能
class TestMeta(type):
def __new__(cls, name, bases, attrs):
# 首先判断该类是不是基类(通过手动定义 abstract 属性来判定)
if attrs.pop("abstract", False):
return super(TestMeta, cls).__new__(cls, name, bases, attrs)
# 否则就是子类,就要判断子类有没有一个叫 _job 的方法
_job = attrs.get("_job", None)
if _job and callable(_job):
return super(TestMeta, cls).__new__(cls, name, bases, attrs)
# 子类为定义 _job 方法
raise TypeError("Test子类必须要定义 _job 方法")
class Test(metaclass=TestMeta):
abstract = True
def __init__(self):
self.salary = []
def work(self):
money = self._job()
self.salary.append(money)
return money
# 这个类会报错
# class SubTestA(Test):
# pass
class SubTestB(Test):
def _job(self):
return 3000
上面的例子中,我们通过元类来检查创建的子类是否包含有_job方法。相比起方法一,该方法必须要求子类定义_job类无论有没有调用过_job方法。但是与Java中的接口相比又少了一点什么?Java中的接口是不可以直接实例化对象的,但是在这个例子中我们可以直接创建Test的对象。这时就该抽象基类上场了。
2.抽象基类实现声明协议
我们可以使用abc模块中的一个装饰器--abstractmethod来装饰一个类的方法使其成为一个抽象方法,拥有抽象方法的类就不可以被实例化(像不像C++中的虚函数)举个例子。
import abc
class Test(metaclass=abc.ABCMeta):
def __init__(self):
self.salary = []
def work(self):
money = self._job()
self.salary.append(money)
return money
@abc.abstractmethod
def _job(self):
raise NotImplementedError("Test子类必须实现 '_job' 方法")
# t = Test() # 报错: TypeError: Can't instantiate abstract class Test with abstract methods _job
# 子类可以被创建,但是不能初始化
class SubTestA(Test):
pass
# sta = SubTestA() # 报错: TypeError: Can't instantiate abstract class SubTestA with abstract methods _job
# 实现抽象函数的子类可以被实例化
class SubTestB(Test):
def _job(self):
return 3000
stb = SubTestB()
对比一下上述三种方法的区别:
| 异常 | 元类 | 抽象基类 |
|---|---|---|
| 在调用方法时产生异常 | 在定义类时产生异常 | 在实例化对象时产生异常 |
Python抽象基类之声明协议的更多相关文章
- Python抽象基类:ABC谢谢你,因为有你,温暖了四季!
Python抽象基类:ABC谢谢你,因为有你,温暖了四季! Python抽象基类:ABC谢谢你,因为有你,温暖了四季! 实例方法.类方法和静态方法 抽象类 具名元组 参考资料 最近阅读了<Pyt ...
- python抽象基类
抽象基类 抽象基类提了一种方式,用以组织对象的层次结构,做出关于所需方法的断言,以及实现其他一些功能 要定义抽象基类,需要使用abc模块,该模块定义了一个元类(ABCMeta) 和一组装饰器(@abs ...
- NSObject class和NSObject protocol的关系(抽象基类与协议)
[转载请注明出处] 1.接口的实现 对于接口这一概念的支持,不同语言的实现形式不同.Java中,由于不支持多重继承,因此提供了一个Interface关键词.而在C++中,通常是通过定义抽象基类的方式来 ...
- 4.6 C++抽象基类和纯虚成员函数
参考:http://www.weixueyuan.net/view/6376.html 总结: 在C++中,可以通过抽象基类来实现公共接口 纯虚成员函数没有函数体,只有函数声明,在纯虚函数声明结尾加上 ...
- Python 接口:从协议到抽象基类
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } 抽象基类的常见用途:实现接口时作为超类使用.然后,说明抽象基类如何检查 ...
- 【Python】【元编程】【从协议到抽象基类】
"""class Vector2d: typecode = 'd' def __init__(self,x,y): self.__x = float(x) self.__ ...
- guxh的python笔记七:抽象基类
1,鸭子类型和白鹅类型 1.1,白鹅类型 白鹅类型对接口有明确定义,比如不可变序列(Sequence),需要实现__contains__,__iter__,__len__,__getitem__,__ ...
- Fluent_Python_Part4面向对象,11-iface-abc,协议(接口),抽象基类
第四部分第11章,接口:从协议到抽象基类(重点讲抽象基类) 接口就是实现特定角色的方法集合. 严格来说,协议是非正式的接口(只由文档约束),正式接口会施加限制(抽象基类对接口一致性的强制). 在Pyt ...
- 流畅python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...
随机推荐
- day12-Python运维开发基础(推导式、生成器与生成器函数)
1. 推导式(列表推导式.集合推导式.字典推导式) # ### 推导式 : 通过一行循环判断,遍历出一系列数据的方式是推导式 """ 推导式一共三种: 列表推导式,集合推 ...
- 解决Eclipse Debug 断点调试的source not found问题
写完代码进行调试的时候,经常会用到断点调试,一步步检测问题,但有时候eclipse有时候无法进入断点,这样就失去了断点的意义,原因是debug无法找到该项目的源代码,解决方法如下 1,打开debug ...
- python列表元组 魔法方法
1.元祖 count() 统计某个字符串的出现次数 tuple.count('22') 返回一个整数 index() 获取某个值出现的位置 2.列表 字符串可以直接转换列表 l ...
- MQTT 协议学习:000-有关概念入门
背景 从本章开始,在没有特殊说明的情况下,文章中的MQTT版本均为 3.1.1. MQTT 协议是物联网中常见的协议之一,"轻量级物联网消息推送协议",MQTT同HTTP属于第七层 ...
- Windows下使用nginx问题
1.下载完成后,解压缩,运行cmd,使用命令进行操作,不要直接双击nginx.exe,不要直接双击nginx.exe,不要直接双击nginx.exe 一定要在dos窗口启动,不要直接双击nginx.e ...
- Python实现的远程登录windows系统功能示例
https://www.jb51.net/article/142326.htm 重点是这几本书要好好读读!: 更多关于Python相关内容感兴趣的读者可查看本站专题:<Python进程与线程操作 ...
- C++面试常见问题——11重载、覆盖、隐藏
重载.覆盖.隐藏 重载 在同一类定义的成员函数中,参数不同的同名函数为重载关系.重载与虚函数无关. class A{ private: int x; public: void fun(int); // ...
- SQL*Loader-128: SQL*Loader-523
错误原因: SQL*Loader-128: unable to begin a sessionORA-01017: invalid username/password; logon denied 解决 ...
- java类 2.18
1. 静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员.如: 如果希望在静态方法中调用非静态变量,可以通过创建类的对象,然后通过对象来访问非静态变量.如: 2. 在普通成员方法中,则可 ...
- Koa2+mongoose
为什么选择Koa koa是Express框架同个公司的产品,是开发者在node7.0版本之后使用promise的api把express再次封装了一次,起名Koa,==Koa=Express+Promi ...