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
这不是真的一致.
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开始并且不是映射的东西.如果函数的文档说它需要任何序列,那几乎总是它需要它.不幸的是,"不是映射"很难测试,原因类似于"序列"难以确定的原因.