From: Guido van Rossum Date: Wed, 12 Feb 2003 03:32:58 +0000 (+0000) Subject: SF #532767: isinstance(x, X) should work when x is a proxy for an X X-Git-Tag: v2.3c1~1902 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=03bc7d3c4d22146b2e28c39e6c2e239137318f0a;p=python SF #532767: isinstance(x, X) should work when x is a proxy for an X instance, as long as x.__class__ is X or a subclass thereof. Did a little cleanup of PyObject_IsInstance() too. --- diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index f481205820..75ad135b5a 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3735,7 +3735,8 @@ def dict_type_with_metaclass(): def meth_class_get(): # Full coverage of descrobject.c::classmethod_get() - if verbose: print "Testing __get__ method of METH_CLASS C methods..." + if verbose: + print "Testing __get__ method of METH_CLASS C methods..." # Baseline arg = [1, 2, 3] res = {1: None, 2: None, 3: None} @@ -3772,6 +3773,32 @@ def meth_class_get(): else: raise TestFailed, "shouldn't have allowed descr.__get__(None, int)" +def isinst_isclass(): + if verbose: + print "Testing proxy isinstance() and isclass()..." + class Proxy(object): + def __init__(self, obj): + self.__obj = obj + def __getattribute__(self, name): + if name.startswith("_Proxy__"): + return object.__getattribute__(self, name) + else: + return getattr(self.__obj, name) + # Test with a classic class + class C: + pass + a = C() + pa = Proxy(a) + verify(isinstance(a, C)) # Baseline + verify(isinstance(pa, C)) # Test + # Test with a new-style class + class C(object): + pass + a = C() + pa = Proxy(a) + verify(isinstance(a, C)) # Baseline + verify(isinstance(pa, C)) # Test + def test_main(): do_this_first() @@ -3859,6 +3886,7 @@ def test_main(): subclass_right_op() dict_type_with_metaclass() meth_class_get() + isinst_isclass() if verbose: print "All OK" diff --git a/Misc/NEWS b/Misc/NEWS index ed4f7cf9ac..d88f753346 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,11 @@ What's New in Python 2.3 alpha 2? Core and builtins ----------------- +- isinstance(x, X): if X is a new-style class, this is now equivalent + to issubclass(type(x), X) or issubclass(x.__class__, X). Previously + only type(x) was tested. (For classic classes this was already the + case.) + - compile(), eval() and the exec statement now fully support source code passed as unicode strings. diff --git a/Objects/abstract.c b/Objects/abstract.c index abc7e709bb..45d22069db 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2040,6 +2040,12 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) static PyObject *__class__ = NULL; int retval = 0; + if (__class__ == NULL) { + __class__ = PyString_FromString("__class__"); + if (__class__ == NULL) + return -1; + } + if (PyClass_Check(cls) && PyInstance_Check(inst)) { PyObject *inclass = (PyObject*)((PyInstanceObject*)inst)->in_class; @@ -2047,6 +2053,19 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) } else if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); + if (retval == 0) { + PyObject *c = PyObject_GetAttr(inst, __class__); + if (c == NULL) { + PyErr_Clear(); + } + else { + if (c != inst->ob_type && PyType_Check(c)) + retval = PyType_IsSubtype( + (PyTypeObject *)c, + (PyTypeObject *)cls); + Py_DECREF(c); + } + } } else if (PyTuple_Check(cls)) { /* Not a general sequence -- that opens up the road to @@ -2060,18 +2079,12 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) if (retval != 0) break; } - return retval; } else { if (!check_class(cls, "isinstance() arg 2 must be a class, type," " or tuple of classes and types")) return -1; - if (__class__ == NULL) { - __class__ = PyString_FromString("__class__"); - if (__class__ == NULL) - return -1; - } icls = PyObject_GetAttr(inst, __class__); if (icls == NULL) { PyErr_Clear();