Protocol 的核心是让类型检查器推导结构契约而非修改运行时行为;它无需显式继承即可匹配内置或第三方类型,仅在静态检查中生效,且成员检查宽泛浅层、不校验返回值协变或嵌套协议。

Python 的 Protocol 不是用来“替代抽象基类”或“实现接口”的工具,它的核心设计初衷是:让类型检查器(如 mypy、pylance)能在不修改运行时行为的前提下,推导出对象是否满足某种结构契约。
为什么需要 Protocol 而不是继承 ABC?
ABC(ABCMeta)要求显式继承和 @abstractmethod,但很多内置类型(如 list、dict)或第三方类根本没继承你的基类——它们只是恰好有 __len__ 和 __getitem__。Protocol 允许你声明“只要长得像,就算数”,而无需改动原类定义。
- 运行时不生效:
Protocol类在运行时只是普通类,不参与isinstance或issubclass判断 - 仅限静态检查:mypy 看到
def func(x: Sized)时,会检查传入对象是否有__len__方法,不管它是不是Sized的子类 - 避免猴子补丁或包装器:不用给
requests.Response加implements(MyProtocol)就能让类型检查通过
Protocol 和 typing.Protocol 的区别
typing.Protocol 是 Python 3.8+ 引入的官方协议基类;此前社区用 typing_extensions.Protocol。二者行为一致,但注意:
- Python typing_extensions,否则报
NameError: name 'Protocol' is not defined -
typing.Protocol是typing模块的一部分,不是abc.ABC的子类,不能混用@abstractmethod - 定义协议方法时,
self参数必须写,即使它不参与结构匹配(mypy 会忽略self类型)
常见误用:把 Protocol 当运行时接口
有人试图用 isinstance(obj, MyProtocol) 或 MyProtocol.register(cls),这会失败——Protocol 不支持运行时注册或检查。
UQCMS云商是一款B2B2C电子商务软件 ,非常适合初创的创业者,个人及中小型企业。程序采用PHP+MYSQL,模板采用smarty模板,二次开发,简单方便,无需学习其他框架就可以自行模板设计。永久免费使用,操作简单,安全稳定。支持PC+WAP+微信三种浏览方式,支持微信公众号。
立即学习“Python免费学习笔记(深入)”;
- 错误示例:
isinstance([1,2], Sized)返回False(尽管 mypy 认为合法) - 正确思路:协议只服务于类型注解 + 静态检查,运行时逻辑仍靠鸭子类型或
hasattr - 若需运行时判断,应单独写辅助函数,比如
def is_sized(obj) -> bool: return hasattr(obj, '__len__')
真正容易被忽略的是:Protocol 的成员访问检查是“宽泛且浅层”的——它只看属性名和方法签名是否存在,不校验返回值类型是否可协变、不深入检查嵌套协议、也不验证 __init__ 是否匹配。这意味着,协议越复杂,越容易在静态检查中“看起来对”,实际运行时报错。









