在查看 CPython 的源代码后,我猜这是一个文档错误,但是,它可能依赖于实现,因此在 Python 错误跟踪器上提出来是一个很好的问题。
具体来说,object.c定义了一个项目的真值如下:
int
PyObject_IsTrue(PyObject *v)
{
Py_ssize_t res;
if (v == Py_True)
return 1;
if (v == Py_False)
return 0;
if (v == Py_None)
return 0;
else if (v->ob_type->tp_as_number != NULL &&
v->ob_type->tp_as_number->nb_bool != NULL)
res = (*v->ob_type->tp_as_number->nb_bool)(v);
else if (v->ob_type->tp_as_mapping != NULL &&
v->ob_type->tp_as_mapping->mp_length != NULL)
res = (*v->ob_type->tp_as_mapping->mp_length)(v);
else if (v->ob_type->tp_as_sequence != NULL &&
v->ob_type->tp_as_sequence->sq_length != NULL)
res = (*v->ob_type->tp_as_sequence->sq_length)(v);
else
return 1;
/* if it is negative, it should be either -1 or -2 */
return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int);
}
我们可以清楚地看到,如果它不是布尔类型、None、序列或映射类型,则 value is value 将始终为 true,这需要设置 tp_as_sequence 或 tp_as_mapping。
幸运的是,查看setobject.c显示集合确实实现了 tp_as_sequence,这表明文档似乎不正确。
PyTypeObject PySet_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"set", /* tp_name */
sizeof(PySetObject), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)set_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
(reprfunc)set_repr, /* tp_repr */
&set_as_number, /* tp_as_number */
&set_as_sequence, /* tp_as_sequence */
0, /* tp_as_mapping */
/* ellipsed lines */
};
dicts也实现了tp_as_sequence,所以看起来虽然不是sequence类型,但是是sequence-like,足够真实。
在我看来,文档应该澄清这一点:类似映射的类型或类似序列的类型将真实地取决于它们的长度。
编辑正如 user2357112 正确指出的那样,tp_as_sequence
并不tp_as_mapping
意味着类型是序列或映射。例如, dict implementstp_as_sequence
和 list implements tp_as_mapping
。