I am looking for something
in the following piece of code so that the isinstance()
check afterwards evaluates to True
in any case:
i = WonderfulClass()
classinfo_of_i = something(i)
isinstance(i, classinfo_of_i) # must evaluate to True
If type
is your answer, I'd be grateful if you explained why. Is type
the real counterpart of isinstance
? Or, asked the other way round, can you think of a case where isinstance(i, type(i))
evaluates to False?
This question arose in the context of the simple way to check if the elements of a list or set are single type?, where we have to go through a sequence and check if all the sequence elements are of the same kind. In this context, elements will be compared to each other. This comparison could be based on type
or based on isinstance
.
Relevant documentation regarding isinstance(object, classinfo)
:
Return true if the object argument is an instance of the classinfo
argument
"Is type the real counterpart of isinstance? Or, asked the other way round, can you think of a case where isinstance(i, type(i)) evaluates to False?"
I can't see any situation where isinstance(i, type(i))
would not return True
.
type()
inspects and returns the type object from an instance so there's no reason why the returned value would fail the isinstance()
check.
Digging into the source of cPython, we see that the code behind type()
simply returns the type object attached to the instance:
v = (PyObject *)o->ob_type;
Py_INCREF(v);
return v;
while the first thing that the isintance() code does is check if the types match exactly (it would later move on to match against classes in the chain of inheritance):
int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{
_Py_IDENTIFIER(__instancecheck__);
PyObject *checker;
/* Quick test for an exact match */
if (Py_TYPE(inst) == (PyTypeObject *)cls)
return 1;
Note that Py_TYPE
is simply a macro that returns obj->ob_type
which matches the return value of type()
. This is defined in Include/object.h as:
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
type()
returns what is expected, but only if you use new style classes (inherit from object
).
Consider the following:
>>> class WonderfulClass(object):
... pass
...
>>> i = WonderfulClass()
>>> isinstance(i,type(i))
True
>>> type(i)
<class '__main__.WonderfulClass'>
>>> class AnotherClass:
... pass
...
>>> z = AnotherClass()
>>> type(z)
<type 'instance'>
>>> isinstance(z,type(z))
True
So although the isinstance
check will work, its worth noting the differences.
First of all, isinstance
is meant to deal with inheritance. E.g.
>>> isinstance("asdfs", object)
True
Here a string was considered an instance of object, as "str" type is a heir of "object" type. So type is not a strict counterpart to isinstance.
Everything is an object in python, so, isinstance(anything, object) should return True for anything and, thus, all the values in your array have a common ancestor in their class hierarchy: object.
If you'd like to directly refer to a more special type/store it in a variable and be able to compare to it, types
module might be of interest to you.
>>> class P:
... pass
...
>>> p = P()
>>> type(p)
<type 'instance'>
>>> p.__class__
<class __main__.P at 0x015A6A78>
>>> class D(object):
... pass
...
>>>
>>> d = D()
>>> type(d)
<class '__main__.D'>
>>> d.__class__
<class '__main__.D'>