There is this code:
class Meta(type):
def __instancecheck__(self, instance):
print("__instancecheck__")
return True
class A(metaclass=Meta):
pass
a = A()
isinstance(a, A) # __instancecheck__ not called
isinstance([], A) # __instancecheck__ called
Why __instancecheck__
is called for []
argument but not for a
argument?
PyObject_IsInstance
does a quick test for exact match.
Objects/abstract.c
:
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
static PyObject *name = NULL;
/* Quick test for an exact match */
if (Py_TYPE(inst) == (PyTypeObject *)cls)
return 1;
// ...
don't like the fast path? you can try this (at your own risk):
>>> import __builtin__
>>> def isinstance(a, b):
... class tmp(type(a)):
... pass
... return __builtin__.isinstance(tmp(), b)
...
>>> __builtin__.isinstance(a, A)
True
>>> isinstance(a, A)
__instancecheck__
True
I think that the PEP describing __instancecheck__()
is faulty. PEP 3119 says:
The primary mechanism proposed here is to allow overloading the built-in functions isinstance() and issubclass(). The overloading works as follows: The call isinstance(x, C) first checks whether
C.__instancecheck__
exists, and if so, callsC.__instancecheck__(x)
instead of its normal implementation.
You can write:
class C:
def do_stuff(self):
print('hello')
C.do_stuff(C())
So based on the quote above from the PEP, you should be able to write
class C:
@classmethod
def __instancecheck__(cls, x):
print('hello')
C.__instancecheck__(C())
--output:--
hello
But isinstance() does not call that method:
class C:
@classmethod
def __instancecheck__(cls, y):
print('hello')
x = C()
isinstance(x, C)
--output:--
<nothing>
The PEP then goes on to say:
These methods are intended to be be called on classes whose metaclass is (derived from) ABCMeta...
Okay, let's try that:
import abc
class MyMeta(abc.ABCMeta): #A metaclass derived from ABCMeta
def __instancecheck__(cls, inst):
print('hello')
return True
class C(metaclass=MyMeta): #A class whose metaclass is derived from ABCMeta
pass
x = C()
C.__instancecheck__(x)
--output:--
hello
But once again isinstance() does not call that method:
isinstance(x, C)
--output:--
<nothing>
Conclusion: PEP 3119 needs to be rewritten--along with the "Data Model" docs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With