What are the differences between type() and isinstance()?
To summarize the contents of other (already good!) answers, isinstance
caters for inheritance (an instance of a derived class is an instance of a base class, too), while checking for equality of type
does not (it demands identity of types and rejects instances of subtypes, AKA subclasses).
Normally, in Python, you want your code to support inheritance, of course (since inheritance is so handy, it would be bad to stop code using yours from using it!), so isinstance
is less bad than checking identity of type
s because it seamlessly supports inheritance.
It's not that isinstance
is good, mind you—it's just less bad than checking equality of types. The normal, Pythonic, preferred solution is almost invariably "duck typing": try using the argument as if it was of a certain desired type, do it in a try
/except
statement catching all exceptions that could arise if the argument was not in fact of that type (or any other type nicely duck-mimicking it;-), and in the except
clause, try something else (using the argument "as if" it was of some other type).
basestring
is, however, quite a special case—a builtin type that exists only to let you use isinstance
(both str
and unicode
subclass basestring
). Strings are sequences (you could loop over them, index them, slice them, ...), but you generally want to treat them as "scalar" types—it's somewhat incovenient (but a reasonably frequent use case) to treat all kinds of strings (and maybe other scalar types, i.e., ones you can't loop on) one way, all containers (lists, sets, dicts, ...) in another way, and basestring
plus isinstance
helps you do that—the overall structure of this idiom is something like:
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
You could say that basestring
is an Abstract Base Class ("ABC")—it offers no concrete functionality to subclasses, but rather exists as a "marker", mainly for use with isinstance
. The concept is obviously a growing one in Python, since PEP 3119, which introduces a generalization of it, was accepted and has been implemented starting with Python 2.6 and 3.0.
The PEP makes it clear that, while ABCs can often substitute for duck typing, there is generally no big pressure to do that (see here). ABCs as implemented in recent Python versions do however offer extra goodies: isinstance
(and issubclass
) can now mean more than just "[an instance of] a derived class" (in particular, any class can be "registered" with an ABC so that it will show as a subclass, and its instances as instances of the ABC); and ABCs can also offer extra convenience to actual subclasses in a very natural way via Template Method design pattern applications (see here and here [[part II]] for more on the TM DP, in general and specifically in Python, independent of ABCs).
For the underlying mechanics of ABC support as offered in Python 2.6, see here; for their 3.1 version, very similar, see here. In both versions, standard library module collections (that's the 3.1 version—for the very similar 2.6 version, see here) offers several useful ABCs.
For the purpose of this answer, the key thing to retain about ABCs (beyond an arguably more natural placement for TM DP functionality, compared to the classic Python alternative of mixin classes such as UserDict.DictMixin) is that they make isinstance
(and issubclass
) much more attractive and pervasive (in Python 2.6 and going forward) than they used to be (in 2.5 and before), and therefore, by contrast, make checking type equality an even worse practice in recent Python versions than it already used to be.
Why use isinstance() instead of type()?
Let me give you a simple example why they can be different:
>>> class A(object): pass
>>> class B(A) : pass
>>> a = A()
>>> b = B()
So far, declared a variable A
and a variable B
derived from A
.
>>> isinstance(a, A)
True
>>> type(a) == A
True
BUT
>>> isinstance(b, A)
True
>>> type(b) == A
False
Difference between isinstance and type in python
First check out all the great answers here.
type() simply returns the type of an object. Whereas, isinstance():
Returns true if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.
Example:
class MyString(str):
pass
my_str = MyString()
if type(my_str) == 'str':
print 'I hope this prints'
else:
print 'cannot check subclasses'
if isinstance(my_str, str):
print 'definitely prints'
Prints:
cannot check subclasses
definitely prints
When to use type() instead of isinstanceof() in python?
They do two different things, you can't really compare them directly. What you've probably read is that you should prefer isinstance
when checking the type of an object at runtime. But that isn't the only use-case for type
(that is the use-case for isinstance
, as its name implies).
What may not be obvious is that type
is a class. You can think of "type" and "class" as synonymous. Indeed, it is the class of class objects, a metaclass. But it is a class just like int
, float
, list
, dict
etc. Or just like a use-defined class, class Foo: pass
.
In its single argument form, it returns the class of whatever object you pass in. This is the form that can be used for type-checking. It is essentially equivalent to some_object.__class__
.
>>> "a string".__class__
<class 'str'>
>>> type("a string")
<class 'str'>
Note:
>>> type(type) is type
True
You might also find this form useful if you ever wanted access to the type of an object itself for other reasons.
In its three-argument form, type(name, bases, namespace)
it returns a new type object, a new class. Just like any other type constructor, just like list()
returns a new list.
So instead of:
class Foo:
bar = 42
def __init__(self, val):
self.val = val
You could write:
def _foo_init(self, val):
self.val = val
Foo = type('Foo', (object,), {'bar':42, '__init__': _foo_init})
isinstance
is a function which checks if... an object is an instance of some type. It is a function used for introspection.
When you want to introspect on the type of an object, usually you will probably use isintance(some_object, SomeType)
, but you might also use type(some_object) is SomeType
. The key difference is that isinstance
will return True
if some_object.__class__
is precisely SomeType
or any of the other types SomeType
inherits from (i.e. in the method resolution order of SomeType
, SomeType.mro()
).
So, isinstance(some_object, SomeType)
is essentially equivalent to some_object.__class__ is SomeType or some_object.__class__ in SomeType.mro()
Whereas if you use type(some_object) is SomeType
, you are only asking some_object.__class__ is SomeType
.
Here's a practical example of when you might want to use type
instead of isinstance
, suppose you wanted to distinguish between int
and bool
objects. In Python, bool
inherits from int
, so:
>>> issubclass(bool, int)
True
So that means:
>>> some_boolean = True
>>> isinstance(some_boolean, int)
True
but
>>> type(some_boolean) is int
False
Inheritance and isinstance
This transitive behavior is how it should work intuitively ...
>>> class Text:
...: pass
...:
...:
>>> class Book(Text):
...: pass
...:
...:
>>> class Novel(Book):
...: pass
...:
...:
>>> n = Novel()
>>> isinstance(n, Novel)
>>> True
>>> isinstance(n, Book)
>>> True
>>> isinstance(n, Text)
>>> True
... because a Novel
is-a Novel
, but also is-a Book
and is-a Text
.
If you want to know whether a class (or instance of a class) is a direct ancestor of another class, you can use the __subclasses__
method of class objects.
>>> Text.__subclasses__()
>>> [__main__.Book]
>>> Book.__subclasses__()
>>> [__main__.Novel]
>>> Novel.__subclasses__()
>>> []
>>>
>>> Novel in Text.__subclasses__()
>>> False
>>> type(n) in Text.__subclasses__()
>>> False
>>> Novel in Book.__subclasses__()
>>> True
>>> type(n) in Book.__subclasses__()
>>> True
edit: YourClass.__bases__
also gives you all direct parent classes.
>>> Novel.__bases__
>>> (__main__.Book,)
How does isinstance work in python for subclasses?
C()
holds a reference to its type, C
, and C
has a tuple C.__mro__
of all its ancestors (including itself). The default type.__instancecheck__
looks through that tuple to see whether an object is an instance of a particular class.
If you follow the function calls down from type.__instancecheck__
, you eventually end up in this loop:
for (i = 0; i < n; i++) {
if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b)
return 1;
Classes in Python do also have information about their subclasses - the C-level PyType_Ready
function informs the base classes about a subclass while readying the subclass. However, searching the inheritance graph downward from the base class would produce pathologically slow behavior for cases where the second argument to isinstance
has a lot of descendants.
isinstance(foo,bar) vs type(foo) is bar
if I'm checking what should ALWAYS BE A BASE OBJECT, what do I really lose from doing type is?
well, it's nice you give the full documented answer in your question, so your answer is you lose nothing! The only times where isinstance()
is necessary is when checking inheritance of a given class compared to another, as you well said and referenced. type()
shall be only used to check whether an instance is exactly of a given base type.
Related Topics
What Exactly Do "U" and "R" String Prefixes Do, and What Are Raw String Literals
What Is the Purpose of the Single Underscore "_" Variable in Python
Configure Flask Dev Server to Be Visible Across the Network
How to Do Relative Imports in Python
How Is Returning the Output of a Function Different from Printing It
How to Check If a String Is a Number (Float)
How Does the @Property Decorator Work in Python
Qtdesigner Changes Will Be Lost After Redesign User Interface
Why Dict.Get(Key) Instead of Dict[Key]
Tkinter Assign Button Command in a For Loop With Lambda
Limiting Floats to Two Decimal Points
Why Is the Output of My Function Printing Out "None"
Error "Microsoft Visual C++ 14.0 Is Required (Unable to Find Vcvarsall.Bat)"
Best Way to Structure a Tkinter Application
Open() in Python Does Not Create a File If It Doesn't Exist