Python
Object Type
Type Comparison
Programming Guide
Python Tips

How to compare type of an object in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Python provides several ways to check an object's type: type() returns the exact type, isinstance() checks against a type or tuple of types (including subclasses), and issubclass() checks class relationships without an instance. The key rule is to prefer isinstance() over type() comparisons in almost all cases because it respects inheritance and is the Pythonic convention.

type() — Exact Type Check

type() returns the exact class of an object:

python
1x = 42
2print(type(x))          # <class 'int'>
3print(type(x) == int)   # True
4print(type(x) is int)   # True
5
6y = True
7print(type(y))          # <class 'bool'>
8print(type(y) == int)   # False — bool is a subclass of int, but type() is exact
9print(type(y) is int)   # False

type() does not consider inheritance. True is a bool, which is a subclass of int, but type(True) == int returns False because the exact type is bool, not int.

isinstance() — Preferred Approach

isinstance() checks whether an object is an instance of a class or any of its subclasses:

python
1x = 42
2print(isinstance(x, int))       # True
3
4y = True
5print(isinstance(y, int))       # True — bool is a subclass of int
6print(isinstance(y, bool))      # True
7print(isinstance(y, (int, str)))  # True — checks against a tuple of types

Use isinstance() when you want to accept any subclass of a type:

python
1class Animal:
2    pass
3
4class Dog(Animal):
5    pass
6
7dog = Dog()
8print(isinstance(dog, Animal))  # True — Dog is a subclass of Animal
9print(type(dog) == Animal)      # False — exact type is Dog, not Animal

issubclass() — Class Relationship Check

issubclass() checks the relationship between two classes (not instances):

python
1print(issubclass(bool, int))      # True
2print(issubclass(int, bool))      # False
3print(issubclass(Dog, Animal))    # True
4print(issubclass(Dog, (Animal, str)))  # True — tuple of types

This is useful for type validation in class hierarchies:

python
def register_handler(handler_class):
    if not issubclass(handler_class, BaseHandler):
        raise TypeError(f"{handler_class} must be a subclass of BaseHandler")

type() is vs type() ==

python
1x = 42
2print(type(x) is int)   # True — identity check (same object)
3print(type(x) == int)    # True — equality check
4
5# Difference matters with metaclasses or dynamic types
6# In practice, 'is' is slightly faster and preferred for type() comparisons

Use is for type comparisons since built-in types are singletons. There is only one int type object in the interpreter.

Checking Against Multiple Types

python
1value = 3.14
2
3# isinstance with a tuple
4if isinstance(value, (int, float)):
5    print("It's a number")
6
7# type() equivalent (more verbose)
8if type(value) in (int, float):
9    print("It's a number")

isinstance() with a tuple is cleaner and handles subclasses correctly.

Type Checking with typing Module

For complex types (generics, unions), use the typing module with runtime checks:

python
1from typing import get_type_hints
2
3def greet(name: str) -> str:
4    return f"Hello, {name}"
5
6hints = get_type_hints(greet)
7print(hints)  # {'name': <class 'str'>, 'return': <class 'str'>}

For runtime validation of complex types, consider typeguard or beartype:

python
1# With typeguard
2from typeguard import check_type
3
4check_type([1, 2, 3], list[int])  # OK
5check_type([1, "two"], list[int])  # TypeCheckError

Duck Typing Alternative

Python's philosophy often favors duck typing — check capabilities rather than types:

python
1# Instead of checking type:
2def process(data):
3    if isinstance(data, list):
4        for item in data:
5            handle(item)
6
7# Prefer duck typing:
8def process(data):
9    try:
10        for item in data:
11            handle(item)
12    except TypeError:
13        handle(data)  # Not iterable, treat as single item

Or use hasattr() and protocol checks:

python
1def save(obj):
2    if hasattr(obj, 'write'):
3        obj.write(data)  # Works with files, StringIO, BytesIO, etc.
4    else:
5        raise TypeError("Object must have a write method")

class Attribute

Every object has a __class__ attribute that is equivalent to type():

python
1x = 42
2print(x.__class__)           # <class 'int'>
3print(x.__class__.__name__)  # 'int'
4print(type(x).__name__)      # 'int'

__name__ is useful for logging or error messages where you need the type name as a string.

Common Pitfalls

  • Using type() when isinstance() is correct: type(x) == SomeClass breaks polymorphism. A Dog instance would fail a type(x) == Animal check. Always use isinstance() unless you explicitly need to exclude subclasses.
  • Comparing type() with a string: type(x) == 'int' always returns False because type() returns a class object, not a string. Use type(x).__name__ == 'int' if you must compare by name, but prefer isinstance(x, int).
  • Forgetting bool is a subclass of int: isinstance(True, int) returns True. If you need to distinguish booleans from integers, check isinstance(x, bool) first since bool is more specific.
  • Not using a tuple with isinstance: Writing isinstance(x, int) or isinstance(x, float) is verbose. Use isinstance(x, (int, float)) instead.
  • Over-checking types in dynamic code: Python is dynamically typed by design. Excessive type checking makes code rigid and less reusable. Use type checks at boundaries (public API inputs) and duck typing internally.

Summary

  • Use isinstance(obj, Type) for most type checks — it respects inheritance and accepts tuples
  • Use type(obj) is Type only when you need an exact type match, excluding subclasses
  • Use issubclass(ClassA, ClassB) to check class relationships without an instance
  • bool is a subclass of int — check isinstance(x, bool) before isinstance(x, int) if distinction matters
  • Prefer duck typing (checking capabilities) over explicit type checking when possible
  • Use type(obj).__name__ when you need the type as a string for logging or error messages

Course illustration
Course illustration

All Rights Reserved.