collections
中的抽象类使用
ABCMeta.register(subclass)
将
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)
Python 2不支持这个功能(来自Lib/_abcoll.py):
Sequence.register(tuple)
Sequence.register(basestring)
Sequence.register(buffer)
Sequence.register(xrange)
...
MutableSequence.register(list)
在Python 3.0中(具体来说是此提交)更改了这种行为:
添加ABC ByteString,它统一了bytes和bytearray(但不包括memoryview)。没有“PEP 3118样式缓冲API对象”的ABC,因为在Python中无法识别它们(除非尝试在它们上使用memoryview())。
PEP 3119中还有更多信息:
这是一个向Python 3000添加抽象基类(ABC)支持的提案。它提议:
[...]
特定的容器和迭代器ABC,将被添加到collections模块中。
该提案的许多思考不是关于ABC的具体机制,与接口或通用函数(GF)相对比,而是关于澄清哲学问题,例如“什么构成了集合”,“什么构成了映射”以及“什么构成了序列”。
[...]用于与ABC一起使用的元类,它允许我们将ABC添加为“虚拟基类”(与C++中的概念不同)到任何类中,包括另一个ABC。这允许标准库定义ABCsSequence和MutableSequence并将其注册为内置类型(例如basestring、tuple和list)的虚拟基类,以便例如以下条件都成立:[...] issubclass(bytearray, MutableSequence)。
仅供参考,memoryview
仅在Python 3.4中被注册为Sequence
的子类:
由于Sequence/Mapping的混淆,因此没有鸭式辨型,所以这是一个简单的缺少显式注册。
(有关详细信息,请参见issue18690)。
Python C API
中的PySequence_Check
不依赖于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
字段(
以bytearray
为例的示例),如果成功,则检查非零的
sq_item
字段(这基本上是getitem -
以bytearray
为例的示例)。
issubclass(bytearray, MutableSequence)
的值为真...但在Python2中并非如此。据我所知,PySequence_Check
将返回正确的结果,因为它不使用元类来确定一个类是否是序列。它查看包含序列方法的struct
字段是否设置。 - Bakuriu