不建议编写抽象基类,容易过度设计
抽象基类与描述符和元类一样,是用于构建框架的工具
一个类可能实现多个接口,从而让实例扮演多个角色。
协议是接口,但不是正式的,因此协议不能像正式接口那样施加限制。一个类可能只实现部分接口。
猴子补丁
Python是动态语言,所以可以在运行时进行修正
class A:
def f(self):
pass
def f(a):
return 'Hello World'
if __name__ == '__main__':
A.f = f
a = A()
print(a.f())
在运行过程中修改类A
的f
方法
鸭子类型
忽略对象的真正类型,转而关注对象有没有实现所需的方法、签名和语义。
在框架之外,鸭子类型通常比类型检查更简单,也更灵活
抽象基类
collections.abc
中有很多有用的抽象类
Python的抽象基类可以使用register
类方法在终端用户的代码中把某个类「声明」为一个抽象基类的「虚拟」子类。
让解释器把调用分派给正确的方法,而不是if/elif/else块硬编码分派逻辑
抽象基类是用于封装框架引入的一般性概念和抽象。基本上不需要自己编写新的抽象基类,只要正确使用现有的抽象基类就能获得99.9%的好处,而不用冒着设计不当导致的巨大风险。
注意:与其他方法描述符一起使用时,abstractmethod
需要放在最里面
虚拟子类
即便不继承,也有办法把一个类注册为抽象基类的虚拟子类。
注册虚拟子类的方法是在抽象基类上调用register
方法。issubclass
和 isinstance
等函数都能识别,但是注册的类不会从抽象基类中继承任何方法或属性。
为了避免运行错误,虚拟子类需要实现所需的全部方法