网易首页 > 网易号 > 正文 申请入驻

Python:协议机制

0
分享至

在 Python 中,语法结构本身并不直接规定对象如何执行行为。语法只确定语言结构,而具体的运行期行为,则由解释器根据既定规则进行解释与分派。这套规则体系,就是“协议机制”。

理解协议机制,关键不在于记忆若干特殊方法名,而在于把握一个核心逻辑:语法结构决定采用哪一种解释规则;对象的类型结构决定是否可以启用该规则,并决定解释路径的入口。

协议不是对象主动执行的行为,而是解释器在特定语法语境下所采用的解释规则集合。

一、什么是协议

在 Python 中,“协议”(protocol)不是对象、不是类型、也不是接口。它不作为独立实体存在,而是解释器在某种语法结构下,用以展开运行期行为的一套规则。

从是否允许对象参与规则实现的角度,协议可以分为两类:

1、用户可扩展的规则

对象可以通过在类型上定义特殊方法(“魔术方法”)参与该规则的实现。这些方法可称为“协议方法”。

2、用户不可扩展的规则

规则完全由解释器内建,不提供对象侧的结构性入口(即对象无法“定义/接管”这条规则的关键步骤)。

通常所说的“协议机制”,指的是允许对象通过协议方法参与解释路径展开的可扩展规则。

二、协议机制的统一工作流程

所有可扩展协议,都遵循同一套运行模型。

1、语法触发

解释器首先识别语法结构,例如:

with obj

语法结构决定解释器将实施哪种规则:

• 调用表达式 →

• 数值运算 →

• for 语句 →

• 点运算 →

• with 语句 →

语法结构只触发选择规则类别,并不决定具体行为。

2、类型入口判定(槽位检查)

在确定协议类别后,解释器进入类型层分派阶段。

首先要解决的问题是:当前对象的类型是否为该协议的解释路径提供入口?

在 CPython 中,这种入口表现为类型对象中的(type slots)。

例如:

• 调用协议 → tp_call

• 迭代协议 → tp_iter

• 数值协议 → tp_as_number->nb_add

• 属性访问 → tp_getattro

• 描述符 → tp_descr_get / tp_descr_set

槽位是类对象内部结构中预先填充的函数指针字段。比如:

        ...

在类对象创建或更新时,解释器会将该方法映射到对应槽位(如 tp_call)。因此,槽位中保存的是解释器层的 C 函数指针,该函数在内部再分派到相应的协议方法(若存在)。

语法结构触发解释器进入对应的协议分派逻辑,该逻辑会从对象类型结构中读取相关槽位。

若协议入口槽位为空,解释器将根据该协议的定义尝试是否存在回退路径;若无可用路径,才会抛出 TypeError。

因此,协议解释路径是否能展开,取决于类型结构是否提供入口以及协议内部规则是否允许展开。

3、解释路径展开

若槽位非空,解释器立即进入协议解释路径:

1、通过槽位调用对应的解释器层分派函数,该函数在内部再调用协议方法(若存在)

2、获取返回值

3、若返回 NotImplemented,尝试替代路径(若协议中存在)

4、若所有路径都尝试失败,抛出 TypeError

例如调用表达式:

obj()

解释路径展开如下:

1、读取 type(obj) 的 tp_call 槽位,通过该槽位对应的调用函数展开调用路径;在普通对象情况下,该路径会进一步分派到 __call__ 方法。

2、返回其结果。

三、解释路径优先级与回退规则

部分协议存在多路径竞争机制。

比如,数值运算协议中包含原地方法、正向方法以及反向方法等,支持多路径竞争。

例如:

a + b

解释路径(严格顺序)为:

1、读取 type(a) 的加法槽位 nb_add,调用相关协议方法 type(a).__add__(b)。

2、若返回 NotImplemented,则尝试反向路径(右操作数兜底)type(b).__radd__(a)。

若 type(b) 是 type(a) 的严格子类,则根据数值协议规则,解释器会优先尝试 type(b).__radd__(a),以保证子类优先。

3、若所有候选仍返回 NotImplemented,抛出 TypeError。

又如原地计算:

a += b

解释路径为:

1、读取 type(a) 的原地加法槽位 nb_inplace_add,调用相关协议方法 type(a).__iadd__(b)。

2、若返回 NotImplemented,回退到上述普通加法解释路径。

在回退发生时,其行为语义等价于执行:

a = a + b

要强调的是,NotImplemented 不是错误。

它是协议协作信号:“我不能处理这个组合,请尝试其它候选路径。”

只有当所有候选路径都返回 NotImplemented,解释器才抛出 TypeError。

因此,协议不仅定义入口,也定义路径优先级与回退规则。

四、协议解释路径何时不会生效

协议是否最终生效,并不只取决于槽位是否非空。

在解释器运行过程中,还存在若干情形会导致协议路径不被触发、被遮蔽或被替代。

1、语法结构未触发该协议

协议必须由对应语法结构触发。

即便类型提供了入口槽位,如果对象从未出现在该语法语境中,协议解释路径就不会被触发。

例如:

        

如果从未用于:

    ...

或:

iter(X())

则迭代协议根本不会触发。

2、类型槽位为空

例如:

a()

调用表达式触发调用协议,但 int 实例所属类型不提供实例级调用入口槽位,因此解释路径无法展开。

这是“入口不存在”的情况。

3、回退路径替代原路径

某些协议包含“主路径 + 回退路径”。

即便主槽位存在,若返回 NotImplemented,解释器会尝试替代路径。

例如前面所讲的数值协议中,正向路径可能被反向路径替代,或者原地路径被普通加法路径替代。

还有一种可能引发槽位级回退的情形。比如:

for x in obj:

正常情况读取 type(obj) 的“迭代”槽位 tp_iter,调用相关协议方法 type(obj).__iter__()

若对象未提供 tp_iter 槽位,但实现了序列槽位(sq_item),解释器会构造一个序列迭代器对象,由其逐次调用 sq_item,直到抛出 IndexError 结束。

4、MRO 改变协议入口的实现来源

在继承场景中,协议路径可能被子类覆盖。

print(len(B()))   # 2

最终槽位绑定到 B.__len__。这里并不是遮蔽,而是类型结构本身发生变化。

小结

在 Python 中,协议是解释器在特定语法语境下采用的解释规则体系。语法结构决定协议类别,类型结构决定是否提供入口,协议内部规则决定解释路径如何展开及如何竞争与回退。协议方法只是对象参与协议的语言接口,真正的行为分派发生在类型层。理解协议机制,就是从解释器的角度理解 Python 的运行逻辑。


点赞有美意,赞赏是鼓励

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
26年坚定持有的十只黑马股,预定翻倍增长!(精选)

26年坚定持有的十只黑马股,预定翻倍增长!(精选)

涨多宝
2026-03-03 11:42:42
0-1耻辱!14亿欧皇马10天2败:已落后巴萨4分 吕迪格再现杀人动作

0-1耻辱!14亿欧皇马10天2败:已落后巴萨4分 吕迪格再现杀人动作

风过乡
2026-03-03 06:25:07
你有知道哪些炸裂的秘密?网友:我有个秘密说出来肯定大家要笑死

你有知道哪些炸裂的秘密?网友:我有个秘密说出来肯定大家要笑死

带你感受人间冷暖
2026-01-29 00:10:05
比达尔:我看不惯德保罗,他太爱耍帅,下次遇到我要狠狠干他一下

比达尔:我看不惯德保罗,他太爱耍帅,下次遇到我要狠狠干他一下

懂球帝
2026-03-03 13:37:16
又有两国下场,英法德也要防御性参战?关键时刻,普京对中喊话

又有两国下场,英法德也要防御性参战?关键时刻,普京对中喊话

知鉴明史
2026-03-02 17:29:36
暴走团老人路上训练,交警劝不听,货车司机“不想走那就别走了”

暴走团老人路上训练,交警劝不听,货车司机“不想走那就别走了”

源远讲堂
2025-07-31 18:13:50
炮火中的A股深度解析:为何远方的战争总让中国股民"买单"?

炮火中的A股深度解析:为何远方的战争总让中国股民"买单"?

A活着
2026-03-03 15:47:06
医生劝告:一 旦吃上降压药,这3种食物马上戒掉,再吃有心梗风险

医生劝告:一 旦吃上降压药,这3种食物马上戒掉,再吃有心梗风险

小胡军事爱好
2026-03-03 10:11:33
在小县城名声很臭是啥体验?网友:脸皮够厚,一切不成问题

在小县城名声很臭是啥体验?网友:脸皮够厚,一切不成问题

解读热点事件
2026-02-04 00:05:07
52中21!布朗尼真有本事!NBA最励志的球二代

52中21!布朗尼真有本事!NBA最励志的球二代

篮球实战宝典
2026-03-02 21:40:48
尾盘操作思路:A股跳水是走是留!一句话直接给告诉你!

尾盘操作思路:A股跳水是走是留!一句话直接给告诉你!

龙行天下虎
2026-03-03 14:53:44
头号援军已到,伊朗扛得住!特朗普咬牙说了一句话,台当局天塌了

头号援军已到,伊朗扛得住!特朗普咬牙说了一句话,台当局天塌了

探源历史
2026-03-03 11:16:03
No!突发神秘怪病!这可是勇士的核心内线

No!突发神秘怪病!这可是勇士的核心内线

篮球实战宝典
2026-03-03 16:41:08
宁愿向美国低头妥协,也不求助中国!俄罗斯到底在布什么局?

宁愿向美国低头妥协,也不求助中国!俄罗斯到底在布什么局?

霁寒飘雪
2026-03-03 17:57:09
金正恩一句话让全球震惊,韩国颤抖,中方第二天就出面发声

金正恩一句话让全球震惊,韩国颤抖,中方第二天就出面发声

青烟小先生
2026-03-02 10:19:13
美对伊朗的行动影响中国石油供应?中方回应

美对伊朗的行动影响中国石油供应?中方回应

澎湃新闻
2026-03-03 18:06:06
《大西洋月刊》丨所有人的目光都投向了古巴

《大西洋月刊》丨所有人的目光都投向了古巴

邸报
2026-03-02 10:33:45
35年前,美国科学家进行实验,4男4女共处一室2年,结果怎么样?

35年前,美国科学家进行实验,4男4女共处一室2年,结果怎么样?

小豫讲故事
2026-03-02 06:00:03
12岁女孩被夸“万里挑一”,网友却看清现实:太勤快注定一生吃苦

12岁女孩被夸“万里挑一”,网友却看清现实:太勤快注定一生吃苦

妍妍教育日记
2026-03-03 18:02:26
哈啰招聘员工要求30岁以下引争议 公司致歉:坚决反对就业歧视

哈啰招聘员工要求30岁以下引争议 公司致歉:坚决反对就业歧视

金融界
2026-03-03 09:54:34
2026-03-03 18:40:49
MediaTea
MediaTea
专业的数字媒体、新媒体技术
1768文章数 79关注度
往期回顾 全部

科技要闻

拥抱AI的"牛马":边提效边自嘲"自费"上班

头条要闻

袭击伊朗后 特朗普首次发表白宫讲话:将不惜一切代价

头条要闻

袭击伊朗后 特朗普首次发表白宫讲话:将不惜一切代价

体育要闻

35轮后积分-7,他们遭遇史上最早的降级

娱乐要闻

谢娜霸气护夫:喊话薛之谦给张杰道歉

财经要闻

特朗普“不惜一切”!全球股债齐崩

汽车要闻

第一梯队辅助驾驶加持 iCAR V27定档3月13日上市

态度原创

时尚
教育
手机
数码
艺术

普通人穿衣真的很简单!单品选对、搭配合理,大方舒适又得体

教育要闻

气象系统2025录用1100多,研究生占50%,南信大294人成信大113人

手机要闻

4499元买iPhone 17e到底值不值:屏幕刷新率仍用60Hz

数码要闻

谷歌Home新增实时搜索功能:Gemini已能理解摄像头实时画面

艺术要闻

Nihad Aghazada:当代阿塞拜疆画家

无障碍浏览 进入关怀版