diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index afb0f877b28..32f9090d60c 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1556,16 +1556,25 @@ order (MRO) for bases """ return 0 def stop(self): raise StopIteration + def return_true(self, thing=None): + return True + def do_isinstance(obj): + return isinstance(int, obj) + def do_issubclass(obj): + return issubclass(int, obj) # It would be nice to have every special method tested here, but I'm # only listing the ones I can remember outside of typeobject.c, since it # does it right. specials = [ - ("__bytes__", bytes, hello, {}), - ("__reversed__", reversed, empty_seq, {}), - ("__length_hint__", list, zero, + ("__bytes__", bytes, hello, set(), {}), + ("__reversed__", reversed, empty_seq, set(), {}), + ("__length_hint__", list, zero, set(), {"__iter__" : iden, "__next__" : stop}), - ("__sizeof__", sys.getsizeof, zero, {}), + ("__sizeof__", sys.getsizeof, zero, set(), {}), + ("__instancecheck__", do_isinstance, return_true, set(), {}), + ("__subclasscheck__", do_issubclass, return_true, + set(("__bases__",)), {}), # These two fail because the compiler generates LOAD_ATTR to look # them up. We'd have to add a new opcode to fix this, and it's # probably not worth it. @@ -1577,7 +1586,9 @@ order (MRO) for bases """ def __getattr__(self, attr, test=self): test.fail("__getattr__ called with {0}".format(attr)) def __getattribute__(self, attr, test=self): - test.fail("__getattribute__ called with {0}".format(attr)) + if attr not in ok: + test.fail("__getattribute__ called with {0}".format(attr)) + return object.__getattribute__(attr) class SpecialDescr(object): def __init__(self, impl): self.impl = impl @@ -1586,7 +1597,7 @@ order (MRO) for bases """ return self.impl.__get__(obj, owner) - for name, runner, meth_impl, env in specials: + for name, runner, meth_impl, ok, env in specials: class X(Checker): pass for attr, obj in env.items(): diff --git a/Objects/abstract.c b/Objects/abstract.c index cc125f5fa47..ae536a78d16 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2574,14 +2574,8 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) Py_LeaveRecursiveCall(); return r; } - if (name == NULL) { - name = PyUnicode_InternFromString("__instancecheck__"); - if (name == NULL) - return -1; - } - checker = PyObject_GetAttr(cls, name); - if (checker == NULL && PyErr_Occurred()) - PyErr_Clear(); + + checker = _PyObject_LookupSpecial(cls, "__instancecheck__", &name); if (checker != NULL) { PyObject *res; int ok = -1; @@ -2644,14 +2638,8 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls) Py_LeaveRecursiveCall(); return r; } - if (name == NULL) { - name = PyUnicode_InternFromString("__subclasscheck__"); - if (name == NULL) - return -1; - } - PyErr_Fetch(&t, &v, &tb); - checker = PyObject_GetAttr(cls, name); - PyErr_Restore(t, v, tb); + + checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name); if (checker != NULL) { PyObject *res; int ok = -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7e81ce66270..0035f6d34c1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -598,14 +598,6 @@ type___instancecheck__(PyObject *type, PyObject *inst) } -static PyObject * -type_get_instancecheck(PyObject *type, void *context) -{ - static PyMethodDef ml = {"__instancecheck__", - type___instancecheck__, METH_O }; - return PyCFunction_New(&ml, type); -} - static PyObject * type___subclasscheck__(PyObject *type, PyObject *inst) { @@ -619,13 +611,6 @@ type___subclasscheck__(PyObject *type, PyObject *inst) } } -static PyObject * -type_get_subclasscheck(PyObject *type, void *context) -{ - static PyMethodDef ml = {"__subclasscheck__", - type___subclasscheck__, METH_O }; - return PyCFunction_New(&ml, type); -} static PyGetSetDef type_getsets[] = { {"__name__", (getter)type_name, (setter)type_set_name, NULL}, @@ -635,8 +620,6 @@ static PyGetSetDef type_getsets[] = { (setter)type_set_abstractmethods, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, {"__doc__", (getter)type_get_doc, NULL, NULL}, - {"__instancecheck__", (getter)type_get_instancecheck, NULL, NULL}, - {"__subclasscheck__", (getter)type_get_subclasscheck, NULL, NULL}, {0} }; @@ -2518,6 +2501,10 @@ static PyMethodDef type_methods[] = { METH_VARARGS | METH_KEYWORDS | METH_CLASS, PyDoc_STR("__prepare__() -> dict\n" "used to create the namespace for the class statement")}, + {"__instancecheck__", type___instancecheck__, METH_O, + PyDoc_STR("__instancecheck__() -> check if an object is an instance")}, + {"__subclasscheck__", type___subclasscheck__, METH_O, + PyDoc_STR("__subclasschck__ -> check if an class is a subclass")}, {0} };