【发布时间】:2017-04-23 00:15:59
【问题描述】:
Python 用魔术方法做了很多事情,其中大部分是某些协议的一部分。我熟悉“迭代器协议”和“数字协议”,但最近偶然发现了 "sequence protocol" 一词。但即使经过一些研究,我也不确定“序列协议”是什么。
例如,C API 函数PySequence_Check 检查(根据文档)是否某个对象实现了“序列协议”。 source code 表示这是一个不是 dict 的类,但实现了 __getitem__ 方法,该方法大致与 iter 上的文档中的说明相同:
[...]必须支持序列协议(
__getitem__()方法,整数参数从 0 开始)。[...]
但以0 开头的要求并不是在PySequence_Check 中“实现”的。
还有collections.abc.Sequence类型,基本上就是说实例要实现__reversed__、__contains__、__iter__和__len__。
但是根据该定义,实现“序列协议”的类不一定是序列,例如"data model" 和抽象类保证序列具有长度。但是一个只实现__getitem__(通过PySequence_Check)的类在使用len(an_instance_of_that_class)时会抛出异常。
有人可以为我澄清一下序列和序列协议之间的区别(如果除了阅读源代码之外还有协议的定义)以及何时使用哪个定义?
【问题讨论】:
-
collections.abc.Sequence需要__getitem__和__len__。其他一切都有 mixin 方法。关于迭代,如果只定义了__getitem__而没有定义__iter__,那么内置的iter会实例化一个从索引0 开始的简单迭代器。要使reversed工作__len__也必须定义,所以它可以从最后一个索引开始。 -
@eryksun 但是一个类不需要
__len__来实现序列协议(就PySequence_Check而言)。实现__len__和__getitem__但不从collections.abc.Sequence继承的类不会传递isinstance(an_instance, Sequence)。这就是触发我的问题的原因。 :) -
这里
PySequence_Check有很好的详细解释:grokbase.com/t/python/python-list/054erpfcep/…
标签: python sequence cpython python-internals