python通过鸭子类型实现接口思想,关注对象行为而非显式类型;typing.protocol提供隐式接口的声明式表达,abc则是其运行时补充工具。

Python的接口思想不依赖显式的接口定义,而是通过鸭子类型(Duck Typing)自然体现:只要一个对象“走起来像鸭子、叫起来像鸭子”,它就可以被当作鸭子使用——换句话说,关注行为而非类型。
鸭子类型就是Python的“隐式接口”
Python没有Java或C#那样的interface关键字,也不强制要求类继承某个抽象基类才能被接受。函数或方法只关心传入对象是否具备所需的方法和属性,而不检查它属于哪个类。
- 例如,内置函数len()能作用于列表、字符串、字典等,只要对象实现了__len__()方法,它就“符合len的接口”
- 同样,for x in obj: 要求obj实现__iter__()或__getitem__()——这是迭代协议,即一种隐式接口
协议(Protocol)让鸭子类型更清晰可读
从Python 3.8起,typing.Protocol 提供了一种声明式方式来表达“期望具备哪些方法”的意图,既不破坏鸭子类型,又增强可读性和类型检查支持。
- 定义一个Drawable协议,只需列出draw()方法签名,无需继承
- 任何实现了draw()的类,即使毫无关联,也能被静态类型检查器识别为Drawable
- 这相当于用代码注释+类型系统“描述接口”,而不是“规定接口”
抽象基类(ABC)是鸭子类型的补充,不是替代
当确实需要运行时类型检查或强制子类实现某些方法时,可以用abc.ABC和@abstractmethod。但它仍是为支持鸭子类型服务的工具。
立即学习“Python免费学习笔记(深入)”;
- collections.abc.Iterable 就是一个典型ABC,它本身不约束具体类型,只检查是否实现了__iter__
- 你可以用isinstance(obj, Iterable)做运行时判断,但绝大多数时候,直接调用iter(obj)并捕获TypeError更Pythonic——这就是鸭子类型的实践:先尝试,失败再处理
写代码时该怎么做?
遵循“宽松输入、明确契约”的原则:
- 函数参数不写: list或: str,而用更通用的类型提示如Sequence、Iterable,甚至自定义Protocol
- 文档字符串中说明“期望对象支持哪些操作”,比如“data需支持__len__()和__getitem__()”
- 避免type(obj) is X或isinstance(obj, X)做类型分流;优先用hasattr()或直接调用再捕获异常










