mirror of
https://github.com/python/cpython.git
synced 2025-08-02 08:02:56 +00:00
Patch by Jim Fulton (code style tweaked a bit) to support
ExtensionClasses in isinstance() and issubclass(). - abstract instance and class protocols are used *only* in those cases that would generate errors before the patch. That is, there's no penalty for the normal case. - instance protocol: an object smells like an instance if it has a __class__ attribute that smells like a class. - class protocol: an object smells like a class if it has a __bases__ attribute that is a tuple with elements that smell like classes (although not all elements may actually get sniffed ;).
This commit is contained in:
parent
9f612f9c5a
commit
668213d3b8
1 changed files with 95 additions and 18 deletions
|
@ -2003,6 +2003,56 @@ static char vars_doc[] =
|
||||||
Without arguments, equivalent to locals().\n\
|
Without arguments, equivalent to locals().\n\
|
||||||
With an argument, equivalent to object.__dict__.";
|
With an argument, equivalent to object.__dict__.";
|
||||||
|
|
||||||
|
static int
|
||||||
|
abstract_issubclass(derived, cls, err, first)
|
||||||
|
PyObject *derived;
|
||||||
|
PyObject *cls;
|
||||||
|
char *err;
|
||||||
|
int first;
|
||||||
|
{
|
||||||
|
static PyObject *__bases__ = NULL;
|
||||||
|
PyObject *bases;
|
||||||
|
int i, l, n;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (__bases__ == NULL) {
|
||||||
|
__bases__ = PyString_FromString("__bases__");
|
||||||
|
if (__bases__ == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
bases = PyObject_GetAttr(cls, __bases__);
|
||||||
|
if (bases == NULL || !PyTuple_Check(bases)) {
|
||||||
|
Py_XDECREF(bases);
|
||||||
|
PyErr_SetString(PyExc_TypeError, err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Py_DECREF(bases);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (derived == cls)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
bases = PyObject_GetAttr(derived, __bases__);
|
||||||
|
if (bases == NULL || !PyTuple_Check(bases)) {
|
||||||
|
Py_XDECREF(bases);
|
||||||
|
PyErr_SetString(PyExc_TypeError, err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = PyTuple_GET_SIZE(bases);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
r = abstract_issubclass(PyTuple_GET_ITEM(bases, i),
|
||||||
|
cls, err, 0);
|
||||||
|
if (r != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_DECREF(bases);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_isinstance(self, args)
|
builtin_isinstance(self, args)
|
||||||
|
@ -2011,28 +2061,50 @@ builtin_isinstance(self, args)
|
||||||
{
|
{
|
||||||
PyObject *inst;
|
PyObject *inst;
|
||||||
PyObject *cls;
|
PyObject *cls;
|
||||||
int retval;
|
PyObject *icls;
|
||||||
|
static PyObject *__class__ = NULL;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &inst, &cls))
|
if (!PyArg_ParseTuple(args, "OO", &inst, &cls))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (PyType_Check(cls)) {
|
|
||||||
retval = ((PyObject *)(inst->ob_type) == cls);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!PyClass_Check(cls)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"second argument must be a class");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyInstance_Check(inst))
|
if (PyClass_Check(cls)) {
|
||||||
retval = 0;
|
if (PyInstance_Check(inst)) {
|
||||||
else {
|
|
||||||
PyObject *inclass =
|
PyObject *inclass =
|
||||||
(PyObject*)((PyInstanceObject*)inst)->in_class;
|
(PyObject*)((PyInstanceObject*)inst)->in_class;
|
||||||
retval = PyClass_IsSubclass(inclass, cls);
|
retval = PyClass_IsSubclass(inclass, cls);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (PyType_Check(cls)) {
|
||||||
|
retval = ((PyObject *)(inst->ob_type) == cls);
|
||||||
|
}
|
||||||
|
else if (!PyInstance_Check(inst)) {
|
||||||
|
if (__class__ == NULL) {
|
||||||
|
__class__ = PyString_FromString("__class__");
|
||||||
|
if (__class__ == NULL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
icls = PyObject_GetAttr(inst, __class__);
|
||||||
|
if (icls != NULL) {
|
||||||
|
retval = abstract_issubclass(
|
||||||
|
icls, cls,
|
||||||
|
"second argument must be a class",
|
||||||
|
1);
|
||||||
|
Py_DECREF(icls);
|
||||||
|
if (retval < 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"second argument must be a class");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"second argument must be a class");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return PyInt_FromLong(retval);
|
return PyInt_FromLong(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2054,13 +2126,18 @@ builtin_issubclass(self, args)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO", &derived, &cls))
|
if (!PyArg_ParseTuple(args, "OO", &derived, &cls))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!PyClass_Check(derived) || !PyClass_Check(cls)) {
|
if (!PyClass_Check(derived) || !PyClass_Check(cls)) {
|
||||||
PyErr_SetString(PyExc_TypeError, "arguments must be classes");
|
retval = abstract_issubclass(
|
||||||
|
derived, cls, "arguments must be classes", 1);
|
||||||
|
if (retval < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/* shortcut */
|
/* shortcut */
|
||||||
if (!(retval = (derived == cls)))
|
if (!(retval = (derived == cls)))
|
||||||
retval = PyClass_IsSubclass(derived, cls);
|
retval = PyClass_IsSubclass(derived, cls);
|
||||||
|
}
|
||||||
|
|
||||||
return PyInt_FromLong(retval);
|
return PyInt_FromLong(retval);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue