什么是Python的序列协议?

MSe*_*ert 16 python cpython sequence python-internals

Python使用魔术方法做了很多,其中大部分是一些协议的一部分.我熟悉"迭代器协议"和"数字协议",但最近偶然发现术语"序列协议".但即使经过一些研究,我也不确定"序列协议"是什么.

例如,C API函数PySequence_Check检查(根据文档)某个对象是否实现了"序列协议".该源代码表明这是一类,这不是一个字典,但实现__getitem__它的方法大致相同,在什么文件iter还指出:

[...]必须支持序列协议(__getitem__()整数参数从0开始的方法).[...]

但是开始的要求0不是"实施"的PySequence_Check.

然后还有的collections.abc.Sequence类型,它基本上是说实例必须实现__reversed__,__contains__,__iter____len__.

但是根据该定义,实现"序列协议"的类不一定是序列,例如序列具有长度的"数据模型"和抽象类garantuee.但是实现__getitem__(传递PySequence_Check)的类在使用时会抛出异常len(an_instance_of_that_class).

有人可以告诉我序列和序列协议之间的区别(如果除了阅读源代码之外还有协议的定义)以及何时使用哪个定义?

use*_*ica 13

这不是真的一致.

这是PySequence_Check:

int
PySequence_Check(PyObject *s)
{
    if (PyDict_Check(s))
        return 0;
    return s != NULL && s->ob_type->tp_as_sequence &&
        s->ob_type->tp_as_sequence->sq_item != NULL;
}
Run Code Online (Sandbox Code Playgroud)

PySequence_Check检查对象是否提供C序列协议,通过表示对象类型的tp_as_sequence成员实现PyTypeObject.该tp_as_sequence成员是一个指向结构的指针,该结构包含一系列用于序列行为的函数,例如sq_item通过数字索引和sq_ass_item项目赋值检索项目.

具体来说,PySequence_Check要求它的参数不是dict,而是它提供的sq_item.

__getitem__Python编写的类型sq_item无论是概念序列还是映射都会提供,因此用Python编写的不继承的映射dict将会通过PySequence_Check.


另一方面,collections.abc.Sequence仅检查对象是否具体继承collections.abc.Sequence或者是否显式register使用其类(或超类)collections.abc.Sequence.如果你只是自己实现一个序列而不做其中任何一个,它就不会通过isinstance(your_sequence, Sequence).此外,注册的大多数类collections.abc.Sequence不支持所有collections.abc.Sequence的方法.总的来说,collections.abc.Sequence它的可靠性远远低于人们通常所期望的那么可靠.


至于什么算作实际中的序列,它通常是任何支持__len____getitem__整数索引从0开始并且不是映射的东西.如果函数的文档说它需要任何序列,那几乎总是它需要它.不幸的是,"不是映射"很难测试,原因类似于"序列"难以确定的原因.

  • 请参阅[问题23864](http://bugs.python.org/issue23864),了解"issubclass"与不是"一招小马"的ABC的限制.它似乎总是不必要地限于我. (2认同)