这章主要讲的是 Python 风格下的协议和接口思想,不是很好归纳,搬运了一下书上的介绍。Python 里面没有给出类似 Java 中的interface
的官方用法。
本章讨论的话题是接口:从鸭子类型的代表特征动态协议,到使接口更明确、能验证实现是否符合规定的抽象基类(Abstract Base Class,ABC)。
本章先说明 Python 社区以往对接口的不严谨理解:部分实现接口通常被认为是可接受的。我们将通过几个示例强调鸭子类型的动态本性,从而澄清这一点。
接着,对抽象基类做了介绍,还为 Python 编程的一个新趋势下了定义。本章余下的内容专门讲解抽象基类。首先,本章说明抽象基类的常见用途:实现接口时作为超类使用。
然后,说明抽象基类如何检查具体子类是否符合接口定义,以及如何使用注册机制声明一个类实现了某个接口,而不进行子类化操作。最后,说明如何让抽象基类自动“识别”任何符合接口的类——不进行子类化或注册。
协议是非正式的
协议是非正式的,只由文档和约定定义,不具备强制性。
白鹅协议(goose typing)
和鸭子协议(duck typing)不同,鸭子协议关注多态性,
不关注类型,只关注方法和接口的相似性。
白鹅协议关注继承,只要是abc的子类,就可以认为是isinstance(abc)
以序列协议
为例,假设我们想实现迭代以及in
运算,通常需要__iter__
和__contains__
方法,但事实上只实现__getitem__
方法也可以。Python 会设法用迭代,通过__getitem__
去实现__iter__
和__contains__
的方法,从而实现in
运算。这说明实现部分协议是可行的。
猴子补丁
使用模板的时候,用修改自己的模板而不去修改源码去实现接口的方法叫做猴子补丁。这和不推荐自己写抽象基类有相似的思想。
抽象基类
直接继承
直接继承需要实现抽象基类的所有虚函数。
注册类(register)
注册类语法:
@抽象基类名.register
注册类不需要完全实现抽象基类的所有虚函数,某种程度上来说更加灵活。扫描二维码关注公众号,回复: 3180838 查看本文章
写了三个类比较:
from abc import ABCMeta, abstractmethod
'''
最简单实现一个抽象类的办法就是继承 ABCMeta
Python 3.6 之前继承抽象基类需要写 metaclass=
'''
class Myabc (metaclass=ABCMeta):
@abstractmethod
def read():
pass
@abstractmethod
def print():
pass
class sample_1(Myabc):
def read():
pass
def print():
pass
class sample_2(Myabc):
def read():
pass
@Myabc.register
class sample_3():
def read():
pass
def read2():
pass
if __name__ == '__main__':
test_1=sample_1()
# test_2=sample_2() 没有完全实现虚函数,报错
test_3=sample_3()