collections
从使用ABCMeta.register(subclass)
到抽象类
将子类注册为这个 ABC 的“虚拟子类”。
在 Python 3中issubclass(bytearray, Sequence)
返回True
,因为bytearray
被显式注册为ByteString
(派生自Sequence
)和MutableSequence
. 请参阅Lib/_collections_abc.py的相关部分:
class ByteString(Sequence):
"""This unifies bytes and bytearray.
XXX Should add all their methods.
"""
__slots__ = ()
ByteString.register(bytes)
ByteString.register(bytearray)
...
MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
Python 2 没有这样做(来自Lib/_abcoll.py):
Sequence.register(tuple)
Sequence.register(basestring)
Sequence.register(buffer)
Sequence.register(xrange)
...
MutableSequence.register(list)
这种行为在 Python 3.0 中发生了变化(特别是在这个提交中):
添加统一字节和字节数组(但不是memoryview)的ABC ByteString 。“PEP 3118 样式缓冲区 API 对象”没有 ABC,因为在 Python 中无法识别它们(除了尝试在它们上使用memoryview()之外
)。
PEP 3119中有更多信息:
这是向 Python 3000 添加抽象基类 (ABC) 支持的提议。它提议: [...] 将容器和迭代器的特定 ABC 添加到集合模块中。
提案中的大部分想法不是关于 ABC 的特定机制,与接口或通用函数 (GFs) 相比,而是关于澄清诸如“什么构成集合”、“什么构成映射”和“是什么构成了一个序列”。
[...] 与 ABC 一起使用的元类,它允许我们将 ABC 作为“虚拟基类”(与 C++ 中的概念不同)添加到任何类,包括另一个 ABC。这允许标准库定义 ABCs Sequence和MutableSequence并将它们注册为内置类型(如basestring、tuple和list )的虚拟基类,因此例如以下条件都为真: [...] issubclass(bytearray,可变序列)。
仅供参考,仅在 Python 3.4memoryview
中注册为子类:Sequence
由于序列/映射混淆,因此没有鸭式输入,因此它是一个简单的缺少显式注册。
(有关详细信息,请参阅issue18690)。
PySequence_Check
来自 Python C API 不依赖于collections
模块:
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;
}
它检查非零tp_as_sequence
字段(例如 forbytearray
),如果成功,则检查非零sq_item
字段(基本上是 getitem - example forbytearray
)。