New submission from Raymond Hettinger <raymond.hettin...@gmail.com>:
Per PEP 3119, "Overloading works as follows: The call isinstance(x, C) first checks whether C.__instancecheck__ exists, and if so, calls C.__instancecheck__(x) instead of its normal implementation." However, this doesn't work because the isinstance() has a bug introduced in Python 3.1 and no one ever noticed. In abstract.c::object_recursive_isinstance(), we have: PyObject *checker = _PyObject_LookupSpecial(cls, &PyId___instancecheck__); However, that function expects an instance as an argument rather than a class. Calling typeobject.c::_PyObject_LookupSpecial() runs: res = _PyType_LookupId(Py_TYPE(self), attrid); Note, the Py_TYPE(self) is intended to move up from an instance to a class, but we're already started with a class, so it moves to the metaclass instead. This code was correct when originally implemented but it did not have tests: if (name == NULL) { name = PyString_InternFromString("__instancecheck__"); if (name == NULL) return -1; } checker = PyObject_GetAttr(cls, name); if (checker == NULL && PyErr_Occurred()) PyErr_Clear(); ------- Demonstration code --------------- class C: def __instancecheck__(self, inst): raise RuntimeError(f'{self=} {inst=}') class P: def __instancecheck__(self, inst): raise RuntimeError(f'{self=} {inst=}') class C(P): pass >>> isinstance(C(), P) # Incorrectly fails to invoke __instancecheck__ True >>> isinstance(C(), P()) # Incorrectly invokes __instancecheck__ Traceback (most recent call last): File "<pyshell#10>", line 1, in <module> isinstance(C(), P()) File "<pyshell#5>", line 3, in __instancecheck__ raise RuntimeError(f'{self=} {inst=}') RuntimeError: self=<__main__.P object at 0x107586c80> inst=<__main__.C object at 0x107587100> ---------- components: Interpreter Core messages: 406187 nosy: rhettinger priority: normal severity: normal status: open title: __instancecheck__ being checked of type(cls) instead of cls versions: Python 3.10, Python 3.11, Python 3.9 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue45791> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com