python写接口规范_Python基础之接口——从协议到抽象基类

导语:本文章记录了本人在学习Python基础之面向对象篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。

本文重点:

1、协议是Python中非正式的接口;

2、了解抽象基类的基本概念以及标准库中的抽象基类;

3、掌握抽象基类的使用方法。

一、协议的高度动态本性

1、协议与接口的基本概念

协议:是Python中非正式的接口,是令Python这种动态类型语言实现多态的方式。

接口:泛指实体把自己提供给外界的一种抽象化物(可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被内部修改而不影响外界其他实体与其交互的方式。

类的接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem__或__add__。

2、协议是非正式的

协议是非正式的,只由文档和约定定义,不具备强制性。

以序列协议为例,假设我们想实现迭代以及in运算,通常需要__iter__和__contains__方法,但事实上只实现__getitem__方法也可以。原因在于当Python发现没有__iter__和__contains__可用时,会转而调用__getitem__方法设法让迭代和in运算符可用。

小结:部分实现协议是有用的。

3、使用猴子补丁在运行时实现协议

在运行时修改类或模块而不改动源码,从而实现目标协议接口的操作就是打猴子补丁。

二、抽象基类

1、基本概念

鸭子类型(duck typing):不关注对象的类型,而是关注对象具有的行为(方法)。鸭子类型像多态一样工作,但是没有继承。

在鸭子类型中,协议风格的接口与继承完全没有关系,实现同一个协议的各个类是相互独立的。

白鹅类型(goose typing):只要cls是抽象基类,即cls的元类是abc.ABCMeta,就可以使用isinstance(obj,cls)。

抽象基类(abstract base class,ABC):抽象基类就是类里定义了纯虚成员函数的类。纯虚函数只提供了接口,并没有具体实现。抽象基类不能被实例化(不能创建对象),通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。简言之,ABC描述的是至少使用一个纯虚函数的接口,从ABC派生出的类将根据派生类的具体特征,使用常规虚函数来实现这种接口。

2、标准库中的抽象基类

(1)collections.abc中抽象基类

collections.abc模块中各个抽象基类的UML类图如下所示:

bV2GMi?w=896&h=474

Iterable、 Container 和 Sized

各个集合应该继承这三个抽象基类, 或者至少实现兼容的协议。

Iterable 通过 __iter__ 方法支持迭代;

Container 通过__contains__ 方法支持 in 运算符;

Sized 通过 __len__ 方法支持len() 函数。

Sequence、 Mapping 和 Set

这三个是主要的不可变集合类型, 而且各自都有可变的子类。

MappingView

在 Python 3 中, 映射方法 .items()、 .keys() 和 .values() 返回的对象分别是 ItemsView、 KeysView 和 ValuesView 的实例。 前两个类还从 Set 类继承了丰富的接口,涉及集合的全部运算符。

Callable 和 Hashable

这两个抽象基类与集合没有太大的关系,只不过因为collections.abc 是标准库中定义抽象基类的第一个模块, 而它们又太重要了,因此才把它们放到 collections.abc 模块中。Callable 或 Hashable 的子类非常少见。这两个抽象基类的主要作用是为内置函数 isinstance 提供支持,以一种安全的方式判断对象能不能调用或散列。

Iterator

是 Iterable 的子类。

(2)numbers包中的数字塔

按照自上而下的线性结构,Number是位于最顶端的超类,详细排序如下:

Number

Complex

Real

Rational

Integral

例如,检查一个数是否是整数,可以使用isinstance(x,numbers.Integral)。

三、抽象基类的使用

1、通过继承声明抽象基类

声明抽象基类最简单的方式是继承abc.ABC或其他抽象基类:Class Student(abc.ABC)

注意:在Python3.0~3.3之间,继承抽象基类的语法是:Class Student(metaclass=abc.ABCMeta)。

2、判断子类是否符合接口定义

在定义抽象基类的子类时,子类需要将继承的抽象基类中的抽象方法具体实现。

3、声明虚拟子类实现抽象基类的接口

虚拟子类:指的是不通过继承而利用注册把一个类变成抽象基类的子类。

注册虚拟之类的方式是调用register方法,语法是@抽象基类名称.register。

经注册后的虚拟子类可以被issubclass和isinstance等函数识别,但是注册的类不会从抽象基类中继承任何方法或属性。具体可通过类属性__mro__查看类的真实继承关系。

四、其它

1、抽象基类中声明抽象类方法需要使用@abc.abstractmethod标记,并且在@abc.abstractmethod和def之间不能有其他装饰器。

2、内省类的继承关系的方法:

__subclasses__():返回类的直接子类列表,不含虚拟子类。

__abcregistry:抽象基类独有的属性,是抽象类注册的虚拟子类的弱引用。

3、__subclasshook__:令抽象基类识别没有进行子类化和注册的类,此方法在abc.Sized中有应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值