From 668213d3b8876a30c5cec84a0d07590374495aba Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 16 Jun 1999 17:28:37 +0000 Subject: 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 ;). --- Python/bltinmodule.c | 111 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 0340e3a..0035cb9 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2003,6 +2003,56 @@ static char vars_doc[] = Without arguments, equivalent to locals().\n\ 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 * builtin_isinstance(self, args) @@ -2011,27 +2061,49 @@ builtin_isinstance(self, args) { PyObject *inst; PyObject *cls; - int retval; + PyObject *icls; + static PyObject *__class__ = NULL; + int retval = 0; if (!PyArg_ParseTuple(args, "OO", &inst, &cls)) return NULL; - if (PyType_Check(cls)) { + + if (PyClass_Check(cls)) { + if (PyInstance_Check(inst)) { + PyObject *inclass = + (PyObject*)((PyInstanceObject*)inst)->in_class; + retval = PyClass_IsSubclass(inclass, cls); + } + } + else if (PyType_Check(cls)) { retval = ((PyObject *)(inst->ob_type) == cls); } - else { - if (!PyClass_Check(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; } - - if (!PyInstance_Check(inst)) - retval = 0; - else { - PyObject *inclass = - (PyObject*)((PyInstanceObject*)inst)->in_class; - retval = PyClass_IsSubclass(inclass, cls); - } + } + else { + PyErr_SetString(PyExc_TypeError, + "second argument must be a class"); + return NULL; } return PyInt_FromLong(retval); } @@ -2054,13 +2126,18 @@ builtin_issubclass(self, args) if (!PyArg_ParseTuple(args, "OO", &derived, &cls)) return NULL; + if (!PyClass_Check(derived) || !PyClass_Check(cls)) { - PyErr_SetString(PyExc_TypeError, "arguments must be classes"); - return NULL; + retval = abstract_issubclass( + derived, cls, "arguments must be classes", 1); + if (retval < 0) + return NULL; + } + else { + /* shortcut */ + if (!(retval = (derived == cls))) + retval = PyClass_IsSubclass(derived, cls); } - /* shortcut */ - if (!(retval = (derived == cls))) - retval = PyClass_IsSubclass(derived, cls); return PyInt_FromLong(retval); } -- cgit v0.12