目录
1.接口和协议
duck-typing -- 鸭子类型
指一种编程风格,它并不依靠查找对象类型来确定其是否具有正确的接口,而是直接调用或使用其方法或属性(“看起来像鸭子,叫起来也像鸭子,那么肯定就是鸭子。”)由于强调接口而非特定类型,设计良好的代码可通过允许多态替代来提升灵活性。鸭子类型避免使用 type()
或 isinstance()
检测。(但要注意鸭子类型可以使用 抽象基类 作为补充。) 而往往会采用 hasattr()
检测或是 EAFP 编程。
鸭子类型:对象的类型无关紧要,只要实现了特定的协议即可。即忽略对象的真正类型,只需要关注对象是否实现了所需的方法、签名和语义。
接口在动态类型语言中是怎么运作的呢?
首先,Python 语言没有 interface 关键字,而且除了抽象基类,每个类都有接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem__或__add__。
按照定义,受保护的属性和私有属性不在接口中。
不要觉得把公开数据属性放入对象的接口中不妥,因为如果需要,总能实现读值方法和设值方法,把数据属性变成特性,使用obj.attr句法的客户代码不会受到影响。
协议是接口,但不是正式的(只由文档和约定定义),因此协议不能像正式接口那样施加限制(本章后面会说明抽象基类对接口一致性的强制)。一个类可能只实现部分接口,这是允许的。
2.序列协议
序列协议是Python最基础的协议之一。即便对象只实现了那个协议最基本的一部分,解释器也会负责任地处理。
比如类中只实现了序列协议的一个方法: __getitem__ 方法,没有实现 __iter__ 和 __contains__ 方法,迭代和in运算符也可用。原因是 Python 会调用 __getitem__ 方法,设法让迭代和in运算符可用。
3.猴子补丁
使用猴子补丁在运行时实现协议
4.抽象基类
abstract base class -- 抽象基类
抽象基类简称 ABC,是对 duck-typing 的补充,它提供了一种定义接口的新方式,相比之下其他技巧例如 hasattr()
显得过于笨拙或有微妙错误(例如使用 魔术方法)。ABC 引入了虚拟子类,这种类并非继承自其他类,但却仍能被 isinstance()
和 issubclass()
所认可;详见 abc
模块文档。Python 自带许多内置的 ABC 用于实现数据结构(在 collections.abc
模块中)、数字(在 numbers
模块中)、流(在 io
模块中)、导入查找器和加载器(在 importlib.abc
模块中)。你可以使用 abc
模块来创建自己的 ABC
抽象基类的本质就是几个特殊方法。
白鹅类型
>>> class Struggle:
def __len__(self):
return 100
>>> from collections import abc
>>> isinstance(Struggle(),abc.Sized)
True
5.标准库中的抽象基类
collections.abc
--- 容器的抽象基类