summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1999-06-16 17:28:37 (GMT)
committerGuido van Rossum <guido@python.org>1999-06-16 17:28:37 (GMT)
commit668213d3b8876a30c5cec84a0d07590374495aba (patch)
tree140cec0510b60e68bfe5037c86f74739c1f004f2 /Python
parent9f612f9c5a1fb1a35cbe360bfbc3d134da268445 (diff)
downloadcpython-668213d3b8876a30c5cec84a0d07590374495aba.zip
cpython-668213d3b8876a30c5cec84a0d07590374495aba.tar.gz
cpython-668213d3b8876a30c5cec84a0d07590374495aba.tar.bz2
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 ;).
Diffstat (limited to 'Python')
-rw-r--r--Python/bltinmodule.c111
1 files 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);
}