环境
? ? ? ? Windows 10
? ? ? ? Cpython 3.7.12
概述
? ? ? ? Python中的富比较可以比较一个对象的两个不同实例,本片笔记主要讲述了在 object.c 中有关富比较的函数。
do_richcompare
????????_Py_SwappedOp[] 就是定义的操作符集,Py_GT、Py_GE、Py_EQ、Py_NE、Py_LT、?Py_LE分别对应 <、<=、==、!=、>、>= 。
????????richcmpfunc 定义在 object.h ,简单来说就是每个类型都需要实现或者指空的一个指针。
? ? ? ? 第一个判断先判断类型不同的 v 与 w,w 的类型是否为 v 类型的子类型,再判断 w 的类型中是否规定了富比较。若上述判断都为真,则置?checked_reverse_op 为 1 ,然后将新分配的?richcmpfunc(相当于 w.操作符v )分配给对象 res ,如果 res 是已实现的,则函数返回对象 res 并减少 res 引用计数。
? ? ? ? 第二个判断如果 v 的类型规定了富比较,那么将新分配的?richcmpfunc(相当于 v.操作符w )分配给对象 res ,如果 res 是已实现的,则函数返回对象 res 并减少 res 引用计数。
? ? ? ? 第三个判断如果?checked_reverse_op 此时仍为 0 且 w 的类型规定了富比较,则将 w 规定的富比较赋给?richcmpfunc 类型的 f ,再将然后将新分配的?richcmpfunc(相当于 w.操作符v )分配给对象 res ,如果 res 是已实现的,则函数返回对象 res 并减少 res 引用计数。
? ? ? ? 如果上述判断中都未返回值则进行一个 switch 判断,这个判断主要的作用是如果 v 和 w 的类型都未规定富比较,那么至少要给 == 或 != 一个合适的默认值,如果未给出则报错并返回空值,若给出则返回对象 res 并增加 res 引用计数。
int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
static const char * const opstrings[] = {"<", "<=", "==", "!=", ">", ">="};
static PyObject *
do_richcompare(PyObject *v, PyObject *w, int op)
{
richcmpfunc f;
PyObject *res;
int checked_reverse_op = 0;
if (v->ob_type != w->ob_type &&
PyType_IsSubtype(w->ob_type, v->ob_type) &&
(f = w->ob_type->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if ((f = v->ob_type->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
case Py_NE:
res = (v != w) ? Py_True : Py_False;
break;
default:
PyErr_Format(PyExc_TypeError,
"'%s' not supported between instances of '%.100s' and '%.100s'",
opstrings[op],
v->ob_type->tp_name,
w->ob_type->tp_name);
return NULL;
}
Py_INCREF(res);
return res;
}
?PyObject_RichCompare
? ? ? ? 这个函数就是进行进一步的判断与断言,再调用?do_richcompare 函数。先来一个断言,若操作符 op 不在规定的操作符集中则终止程序,然后判断 v 和 w 有没有为空的,有则报错并返回空值,接着再判断是否正在进行 v 与 w 的富比较,是则返回空值。经过上述操作,再调用?do_richcompare 函数并将其返回值赋给对象 res,然后返回 res( Py_LeaveRecursiveCall 是用来结束 Py_EnterRecursiveCall 异常处理的)
PyObject *
PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
assert(Py_LT <= op && op <= Py_GE);
if (v == NULL || w == NULL) {
if (!PyErr_Occurred())
PyErr_BadInternalCall();
return NULL;
}
if (Py_EnterRecursiveCall(" in comparison"))
return NULL;
res = do_richcompare(v, w, op);
Py_LeaveRecursiveCall();
return res;
}
|