Python基础之接口——从协议到抽象基类

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

本文重点:安全

一、协议是Python中非正式的接口;
二、了解抽象基类的基本概念以及标准库中的抽象基类;
三、掌握抽象基类的使用方法。

1、协议的高度动态本性

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

协议:是Python中非正式的接口,是令Python这种动态类型语言实现多态的方式。
接口:泛指实体把本身提供给外界的一种抽象化物(能够为另外一实体),用以由内部操做分离出外部沟通方法,使其能被内部修改而不影响外界其余实体与其交互的方式。
类的接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem__或__add__。app

二、协议是非正式的

协议是非正式的,只由文档和约定定义,不具有强制性。
以序列协议为例,假设咱们想实现迭代以及in运算,一般须要__iter__和__contains__方法,但事实上只实现__getitem__方法也能够。缘由在于当Python发现没有__iter__和__contains__可用时,会转而调用__getitem__方法设法让迭代和in运算符可用。
小结:部分实现协议是有用的。ssh

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

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

2、抽象基类

一、基本概念

鸭子类型(duck typing):不关注对象的类型,而是关注对象具备的行为(方法)。鸭子类型像多态同样工做,可是没有继承。
在鸭子类型中,协议风格的接口与继承彻底没有关系,实现同一个协议的各个类是相互独立的。学习

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

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

二、标准库中的抽象基类

(1)collections.abc中抽象基类
collections.abc模块中各个抽象基类的UML类图以下所示:
collections.abc模块中各个抽象基类的UML类图对象

  • 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)。继承

3、抽象基类的使用

一、经过继承声明抽象基类

声明抽象基类最简单的方式是继承abc.ABC或其余抽象基类:Class Student(abc.ABC)
注意:在Python3.0~3.3之间,继承抽象基类的语法是:Class Student(metaclass=abc.ABCMeta)。

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

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

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

虚拟子类:指的是不经过继承而利用注册把一个类变成抽象基类的子类。
注册虚拟之类的方式是调用register方法,语法是@抽象基类名称.register。
经注册后的虚拟子类能够被issubclass和isinstance等函数识别,可是注册的类不会从抽象基类中继承任何方法或属性。具体可经过类属性__mro__查看类的真实继承关系。

4、其它

一、抽象基类中声明抽象类方法须要使用@abc.abstractmethod标记,而且在@abc.abstractmethod和def之间不能有其余装饰器。二、内省类的继承关系的方法:__subclasses__():返回类的直接子类列表,不含虚拟子类。__abcregistry:抽象基类独有的属性,是抽象类注册的虚拟子类的弱引用。三、__subclasshook__:令抽象基类识别没有进行子类化和注册的类,此方法在abc.Sized中有应用。

相关文章
相关标签/搜索