抽象基类之--声明协议

上回讲了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抽象基类之声明协议的更多相关文章

  1. Python抽象基类:ABC谢谢你,因为有你,温暖了四季!

    Python抽象基类:ABC谢谢你,因为有你,温暖了四季! Python抽象基类:ABC谢谢你,因为有你,温暖了四季! 实例方法.类方法和静态方法 抽象类 具名元组 参考资料 最近阅读了<Pyt ...

  2. python抽象基类

    抽象基类 抽象基类提了一种方式,用以组织对象的层次结构,做出关于所需方法的断言,以及实现其他一些功能 要定义抽象基类,需要使用abc模块,该模块定义了一个元类(ABCMeta) 和一组装饰器(@abs ...

  3. NSObject class和NSObject protocol的关系(抽象基类与协议)

    [转载请注明出处] 1.接口的实现 对于接口这一概念的支持,不同语言的实现形式不同.Java中,由于不支持多重继承,因此提供了一个Interface关键词.而在C++中,通常是通过定义抽象基类的方式来 ...

  4. 4.6 C++抽象基类和纯虚成员函数

    参考:http://www.weixueyuan.net/view/6376.html 总结: 在C++中,可以通过抽象基类来实现公共接口 纯虚成员函数没有函数体,只有函数声明,在纯虚函数声明结尾加上 ...

  5. Python 接口:从协议到抽象基类

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 15.0px Helvetica } 抽象基类的常见用途:实现接口时作为超类使用.然后,说明抽象基类如何检查 ...

  6. 【Python】【元编程】【从协议到抽象基类】

    """class Vector2d: typecode = 'd' def __init__(self,x,y): self.__x = float(x) self.__ ...

  7. guxh的python笔记七:抽象基类

    1,鸭子类型和白鹅类型 1.1,白鹅类型 白鹅类型对接口有明确定义,比如不可变序列(Sequence),需要实现__contains__,__iter__,__len__,__getitem__,__ ...

  8. Fluent_Python_Part4面向对象,11-iface-abc,协议(接口),抽象基类

    第四部分第11章,接口:从协议到抽象基类(重点讲抽象基类) 接口就是实现特定角色的方法集合. 严格来说,协议是非正式的接口(只由文档约束),正式接口会施加限制(抽象基类对接口一致性的强制). 在Pyt ...

  9. 流畅python学习笔记:第十一章:抽象基类

    __getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...

随机推荐

  1. 神机iPhone6停产,苹果产业链应该感谢它还是痛恨它?

    据国内媒体报道,一些苹果上游供应商已经接到通知,iPhone6系列将会在5月底彻底停产,一时间,竟在网络上引发汹涌的怀念之情.iPhone6的特别之处在于它是苹果第一款大屏幕的智能手机,标志着库克彻底 ...

  2. 树莓派frp添加为服务管理

    1.下载frp https://github.com/fatedier/frp/releases 我是1代的B+,下载arm版的,新的可以用arm64的 frp_0.29.0_linux_arm.ta ...

  3. Oracle笔记--Sql语句

    1.SQL的三种类型语句: --1)DML(Data Manipulation Language)数据操纵语言 --2)DDL(Data Definition Language):数据定义语言 --3 ...

  4. IOS 3种内省方法

    IOS提供了3种内省方法 isKindOfClass 检查当前实例是否为某类及其子类 UIView *b = [UIView new]; //... id a = b; if ([a isMember ...

  5. hdfs的bug纪录, Unexpected block state

      今早遇到一个bug,提交 spark job 失败.说 hdfs 在 safe mode状态,不允许创建和删除文件. 然后发现 hdfs 的日志文件不断滚动,几乎每秒钟100M的速度打日志,当时没 ...

  6. CentOS7虚拟机配置、Hadoop搭建、wordCount DEMO运行

    安装虚拟机 最开始先安装虚拟机,我是12.5.7版本,如果要跟着我做的话,版本最好和我一致,不然后面可能会出一些莫名其妙的错误,下载链接如下(注册码也在里面了): 链接:https://pan.bai ...

  7. python2.7 操作ceph-cluster S3对象接口 实现: 上传 下载 查询 删除 顺便使用Docker装个owncloud 实现UI管理

    python version:    python2.7 需要安装得轮子: botofilechunkio command: yum install python-pip&& pip ...

  8. obtainFreshBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  9. Linux基础命令、软件安装

    常用命令 查看当前系统中存在哪些shell cat /etc/shells [root@** ~]# cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /us ...

  10. python数据分析基础

    ---恢复内容开始--- Python数据分析基础(1) //2019.07.09python数据分析基础总结1.python数据分析主要使用IDE是Pycharm和Anaconda,最为常用和方便的 ...