接口,协议和鸭子类型

摘自《流畅的Python》10.3 协议和鸭子类型;杂谈:把协议当作非正式的接口;11.1 Python文化中的接口和协议

Python中除了抽象基类,每个类都有接口:类实现或继承的公开属性(方法或数据属性),包括特殊方法,如__getitem__ 或__add__。

按照定义,受保护的属性和私有属性不在接口中:即便“受保护的”属性也只是采用命名约定实现的(单个前导下划线);私有属性可以轻松地访问。

关于接口,这里有个实用的补充定义:接口是实现特定角色的方法集合。一个类可能会实现多个接口,从而让实例扮演多个角色。Python 文档中的“文件类对象”或“可迭代对象”就是这个意思,这种说法指的不是特定的类。

在面向对象编程中,协议是非正式的接口,只在文档中定义,在代码中不定义。例如,Python 的序列协议只需要__len__ 和__getitem__ 两个方法。任何类(如Spam),只要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方。Spam 是不是哪个类的子类无关紧要,只要提供了所需的方法即可。我们说它是序列,因为它的行为像序列,这才是重点。

不要检查它是不是鸭子、它的叫声像不像鸭子、它的走路姿势像不像鸭子,等等。具体检查什么取决于你想使用语言的哪些行为。

协议是接口,但不是正式的(只由文档和约定定义),因此协议不能像正式接口那样施加限制(本章后面会说明抽象基类对接口一致性的强制)。因此如果你知道类的具体使用场景,通常只需要实现一个协议的部分。例如,为了支持迭代,只需实现__getitem__ 方法,没必要提供__len__ 方法。

在Python 文档中,如果看到“文件类对象”这样的表述,通常说的就是协议。这是一种简短的说法,意思是:“行为基本与文件一致,实现了部分文件接口,满足上下文相关需求的东西。”

我们把协议定义为非正式的接口,是让Python 这种动态类型语言实现多态的方式。
 

猜你喜欢

转载自blog.csdn.net/Airfrozen/article/details/104377016
今日推荐