type() vs. isinstance()
Python is a dynamically typed language. A variable, initially created as a string, can be later reassigned to an integer or a float. And the interpreter won’t complain:
name = "Sebastian"
# Dynamically typed language lets you do this:
name = 42
name = None
name = Exception()
It’s quite common to see code that checks variable’s type. Maybe you want to accept both a single element and a list of items and act differently in each case. That’s what the SMTP.sendmail() from the smtplib does. It checks if the recipient
is a string or a list of strings and sends one or more emails.
To check the type of a variable, you can use either type() or isinstance() built-in function. Let’s see them in action:
>>> variable = "hello"
>>> type(variable) is str
True
>>> isinstance(variable, str)
True
Let’s compare both methods’ performance:
$ python -m timeit -s "variable = 'hello'" "type(variable) is int"
2000000 loops, best of 5: 102 nsec per loop
$ python -m timeit -s "variable = 'hello'" "isinstance(variable, str)"
5000000 loops, best of 5: 72.8 nsec per loop
type
is 40% slower (102/72.8 = 1.40).
We could use type(variable) == str
instead. It would work, but it's a bad idea:
==
should be used when you want to check the value of a variable. We would use it to see if the value ofvariable
is equal to"hello"
. But when we want to check ifvariable
is a string,is
operator is more appropriate. For a more detailed explanation of when to use one or the other, check this article.==
is slower:
$ python -m timeit -s "variable = 'hello'" "type(variable) == str"
2000000 loops, best of 5: 114 nsec per loop
Difference between isinstance
and type
Speed is not the only difference between these two functions. There is actually an important distinction between how they work:
type
only returns the type of an object (its class). We can use it to check ifvariable
is of a typestr
.isinstance
checks if a given object (first parameter) is:
- an instance of a class specified as a second parameter. For example, isvariable
an instance of thestr
class?
- or an instance of a subclass of a class specified as a second parameter. In other words — isvariable
an instance of a subclass ofstr
?
What does it mean in practice? Let’s say we want to have a custom class that acts like a list but has some additional methods. So we might subclass the list
type and add custom functions inside:
class MyAwesomeList(list):
# Add additional functions here
But now the type
and isinstance
return different results if we compare this new class to a list!
>>> my_list = MyAwesomeList()
>>> type(my_list) is list
False
>>> isinstance(my_list, list)
True
We get different results because isinstance
checks if my_list
is an instance of list
(it's not) or a subclass of list
(it is, because MyAwesomeList
is a subclass of list
). If you forget about this difference, it can lead to some subtle bugs in your code.
A better way to create a custom list-like class
If you really need to create a custom class that behaves like a list but has some additional features, check out the collections module. It contains classes like
UserList
,UserString
, orUserDictionary
. They are specifically designed to be subclassed when you want to create something that acts like a list, string, or a dictionary. If you try to subclass thelist
class, you might quickly fall into a rabbit hole of patching and reimplementing the existing methods just to make your subclass work as expected. Trey Hunner as a good article explaining this problem called "The problem with inheriting from dict and list in Python".
Conclusions
isinstance
is usually the preferred way to compare types. It's not only faster but also considers inheritance, which is often the desired behavior. In Python, you usually want to check if a given object behaves like a string or a list, not necessarily if it's exactly a string. So instead of checking for string and all it's custom subclasses, you can just use isinstance
.
On the other hand, when you want to explicitly check that a given variable is of a specific type (and not its subclass) — use type
. And when you use it, use it like this: type(var) is some_type
not like this: type(var) == some_type
.
And before you start checking types of your variables everywhere throughout your code, check out why “Asking for Forgiveness” might be a better way.
Originally published at https://switowski.com.