Checking Types in Python
Need to know the type of an object? Let me make a brief argument: No, you don't. Just use the object as if it was whatever you expect it to be, and handle any errors that result.
On the other hand, type-checking is convenient, easy to implement, and can save your life when debugging. Sometimes there isn't an obvious other way to attack a problem. (Look for one first though. Really.)
You have a few choices on how to type-check: the built-in functions type and isinstance and the instance property __class__. To compare the object to known classes, you can compare to the class directly or import the 'types' module (safe to do in your global scope) to get access to some types that don't provide user-accessible classes (like functions).
Before we start, note that Python has two types of classes: 'new-style' classes which inherit from the object class, and 'old-style' classes which don't. Most (all?) native Python types are now new-style classes, but classes you've created probably aren't.
Let's try some experiments, trying to print out the name of a class, and then comparing the type to a known class. Say we have the following classes and instances defined:
# 'sLet's print out the name of the class using type and __class__. There's no way to do this with isinstance.:
1from types import * 2 3# Instances of new-style classes 4class NewClass(object): pass 5 6new_class_instance = NewClass() 7 8def function(): pass 9 10string = 'This is a string!' 11 12# Instances of old-style classes 13class OldClass: pass 14 15old_class_instance = OldClass()
# 'sIt looks like type doesn't work for old-style classes. Now let's try checking against a known class or type, using type, isinstance, and __class__:
1print type(new_class_instance) 2print new_class_instance.__class__ 3# both print "<class '__main__.new_class'>" 4 5print type(function) 6print function.__class__ 7# both print "<type 'function'>" 8 9print type(string) 10print string.__class__ 11# both print "<type 'str'>" 12 13print type(old_class) 14# prints "<type 'instance'>" 15 16print old_class.__class__ 17# prints something like "class __main__.OldClass at 0x00F7F" 18# Note that this is different than what was printed by type()
# 'sApparently, type is completely useless for both type printing and type comparisons, as it can't understand old-style classes while __class__ can.
1type(new_class_instance) == NewClass 2isinstance(new_class_instance, NewClass) 3new_class_instance.__class__ == NewClass 4# All return True 5 6type(function) == FunctionType # from 'types' module 7isinstance(function, FunctionType) 8function.__class__ == FunctionType 9# All return True 10 11type(string) == str # we could also use StringType from 'types' module 12isinstance(string, str) 13string.__class__ == str 14# All return True 15 16type(old_class_instance) == OldClass 17# Returns False, even though old_class_instance is an instance of OldClass. 18# 'type' just can't understand these. 19 20isinstance(old_class_instance, OldClass) 21old_class_instance.__class__ == OldClass 22# Both return True as expected
__class__ is messy, but is the only method that both works for both types of classes and will print out the name of the class if desired. It is the best choice for debugging, when you have no idea what type of object you're looking at.
isinstance also works on all objects. It also has another couple of perks: it actually checks to see if your object is an instance of a class or subclass of the class you pass it. Generally if you're type-checking you're interested in the existence of a behavior or method, and all subclasses of the target class will probably have it. So, isinstance is more accurate. Additionally, you can pass it a tuple of classes, and it will check against all of them. These perks make it the best choice for legitimate type-checking in a real program.
Here's a summary of what we found: