Python 的序列协议是什么?
What is Python's sequence protocol?
Python 用魔术方法做了很多,其中大部分是某些协议的一部分。我熟悉“迭代器协议”和“数字协议”,但最近偶然发现了术语 "sequence protocol"。但即使经过一些研究,我也不确定“序列协议”是什么。
例如 C API 函数 PySequence_Check
checks (according to the documentation) if some object implements the "sequence protocol". The source code indicates that this is a class that's not a dict but implements a __getitem__
method which is roughly identical to what the documentation on iter
也声明:
[...]must support the sequence protocol (the __getitem__()
method with integer arguments starting at 0).[...]
但是以 0
开头的要求在 PySequence_Check
中并未“实现”。
然后还有collections.abc.Sequence
类型,基本上说实例必须实现__reversed__
、__contains__
、__iter__
和__len__
。
但根据该定义,实现“序列协议”的 class 不一定是序列,例如 "data model" 和抽象 class 保证序列具有长度。但是 class 只是实现 __getitem__
(传递 PySequence_Check
)在使用 len(an_instance_of_that_class)
.
时抛出异常
有人可以为我澄清序列和序列协议之间的区别(如果除了阅读源代码之外还有协议的定义)以及何时使用哪个定义?
不太一致。
这里是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;
}
PySequence_Check
检查对象是否提供 C 序列协议,通过 PyTypeObject
中表示对象类型的 tp_as_sequence
成员实现。这个 tp_as_sequence
成员是一个指向结构的指针,该结构包含一系列用于序列行为的函数,例如用于通过数字索引检索项目的 sq_item
和用于项目分配的 sq_ass_item
。
具体来说,PySequence_Check
要求其参数不是字典,并且它提供 sq_item
.
在 Python 中写有 __getitem__
的类型将提供 sq_item
,无论它们在概念上是序列还是映射,所以在 Python 中写的映射不'继承自 dict
将传递 PySequence_Check
。
另一方面,collections.abc.Sequence
只检查一个对象是否具体地继承自 collections.abc.Sequence
或者它的 class(或一个 superclass)是否明确地 register
编辑为 collections.abc.Sequence
。如果你只是自己实现一个序列而不做这些事情,它不会通过 isinstance(your_sequence, Sequence)
。此外,大多数在 collections.abc.Sequence
注册的 classes 并不支持 collections.abc.Sequence
的所有方法。总的来说,collections.abc.Sequence
远不如人们通常预期的那样可靠。
至于在实践中什么算作序列,它通常是任何支持 __len__
和 __getitem__
且整数索引从 0 开始并且不是映射的东西。如果一个函数的文档说它需要任何序列,那几乎总是它所需要的。不幸的是,“不是一个映射”很难测试,原因类似于“是一个序列”很难确定。
要使类型符合序列协议,必须满足这 4 个条件:
按索引检索元素
item = seq[index]
按值查找项目
index = seq.index(item)
计数项目
num = seq.count(item)
产生一个反转序列
r = reversed(seq)
Python 用魔术方法做了很多,其中大部分是某些协议的一部分。我熟悉“迭代器协议”和“数字协议”,但最近偶然发现了术语 "sequence protocol"。但即使经过一些研究,我也不确定“序列协议”是什么。
例如 C API 函数 PySequence_Check
checks (according to the documentation) if some object implements the "sequence protocol". The source code indicates that this is a class that's not a dict but implements a __getitem__
method which is roughly identical to what the documentation on iter
也声明:
[...]must support the sequence protocol (the
__getitem__()
method with integer arguments starting at 0).[...]
但是以 0
开头的要求在 PySequence_Check
中并未“实现”。
然后还有collections.abc.Sequence
类型,基本上说实例必须实现__reversed__
、__contains__
、__iter__
和__len__
。
但根据该定义,实现“序列协议”的 class 不一定是序列,例如 "data model" 和抽象 class 保证序列具有长度。但是 class 只是实现 __getitem__
(传递 PySequence_Check
)在使用 len(an_instance_of_that_class)
.
有人可以为我澄清序列和序列协议之间的区别(如果除了阅读源代码之外还有协议的定义)以及何时使用哪个定义?
不太一致。
这里是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;
}
PySequence_Check
检查对象是否提供 C 序列协议,通过 PyTypeObject
中表示对象类型的 tp_as_sequence
成员实现。这个 tp_as_sequence
成员是一个指向结构的指针,该结构包含一系列用于序列行为的函数,例如用于通过数字索引检索项目的 sq_item
和用于项目分配的 sq_ass_item
。
具体来说,PySequence_Check
要求其参数不是字典,并且它提供 sq_item
.
在 Python 中写有 __getitem__
的类型将提供 sq_item
,无论它们在概念上是序列还是映射,所以在 Python 中写的映射不'继承自 dict
将传递 PySequence_Check
。
另一方面,collections.abc.Sequence
只检查一个对象是否具体地继承自 collections.abc.Sequence
或者它的 class(或一个 superclass)是否明确地 register
编辑为 collections.abc.Sequence
。如果你只是自己实现一个序列而不做这些事情,它不会通过 isinstance(your_sequence, Sequence)
。此外,大多数在 collections.abc.Sequence
注册的 classes 并不支持 collections.abc.Sequence
的所有方法。总的来说,collections.abc.Sequence
远不如人们通常预期的那样可靠。
至于在实践中什么算作序列,它通常是任何支持 __len__
和 __getitem__
且整数索引从 0 开始并且不是映射的东西。如果一个函数的文档说它需要任何序列,那几乎总是它所需要的。不幸的是,“不是一个映射”很难测试,原因类似于“是一个序列”很难确定。
要使类型符合序列协议,必须满足这 4 个条件:
按索引检索元素
item = seq[index]
按值查找项目
index = seq.index(item)
计数项目
num = seq.count(item)
产生一个反转序列
r = reversed(seq)