Of course, polymorphism can make things a bit more complicated when it comes to determining exactly what type of object is stored in a variable. Thankfully, Python includes a few easy ways to determine what type of object is really stored in a variable, helping us know what methods and attributes are available.
Determining Data Type
Let’s go back to the previous example from the last page, where we had placed all of our objects in a list.
from Car import * from Airplane import * from Truck import * class Main: @staticmethod def main(): vehicles =  vehicles.append(Airplane("Plane", 123, 45)) vehicles.append(Car("Car", 4)) vehicles.append(Truck("Truck", 157)) for v in vehicles: print(v.name) print(v.describe()) print(v.move(10)) # main guard if __name__ == "__main__": Main.main()
What if we’d like to call the
honk_horn() method, but only if the object supports that method? To do that, we’ll need to determine what type of object is stored in the variable. So, we can update the code as shown below:
from Car import * from Airplane import * from Truck import * from MotorVehicle import * class Main: @staticmethod def main(): vehicles =  vehicles.append(Airplane("Plane", 123, 45)) vehicles.append(Car("Car", 4)) vehicles.append(Truck("Truck", 157)) for v in vehicles: try: print(v.honk_horn()) except AttributeError: print(v.name + " can't honk!") # main guard if __name__ == "__main__": Main.main()
Here, we are doing two very important operations. First, we are using
isinstance(v, MotorVehicle) to determine if the object stored in
v is actually an object that is a
MotorVehicle or one of its child classes. So, for objects created from the
Truck classes, this operation will return
True since both
Truck are child classes of
Then, once we’ve determined that we can treat the object
v as a
MotorVehicle, we can call methods and access attributes and properties that are available in the
MotorVehicle class. We don’t have to do anything else in Python for this to work.
It is important to note, however, that if we try to access a method, attribute or property that isn’t available, we’ll get an exception, the AttributeError. So use a Try-Except statement and be prepared to catch an exception if it fails. You may wonder why you don’t “look before you leap” with an IF and
isinstance(). It is not conventional in dynamically typed language to do so.
We can also inspect the type of an object in a more open-ended manner using the
type function, which returns an object representing the argument’s type, printed in the format
<class c>, where
c may be
'str', or the name of any other built-in or user-defined type. For example,
type(1) == int would evaluate to
True, and the Python interpreter would print the result of
<class 'str'>. However, this method of examining types doesn’t allow us to recover any information about class hierarchies; the type returned is always the most specific applicable type, so we can’t use
type to see whether an instance of a given class can also be treated as an instance of some other class.
Place the code above in the
Main class and see what it does. Can you come up with any other programs that would require us to check the types of objects?