Question

How to Check an Object’s Type in Python with type() and isinstance()

pythontypes

Question

How can you check whether an object is a given type in Python, including whether it inherits from that type?

For example, how can you determine whether an object o should be treated as a str?

o = "hello"

More generally:

  • How do you check whether an object is exactly a specific type?
  • How do you check whether an object is an instance of a type or any subclass of that type?

This question is about checking Python object types correctly. It is not about converting strings to numbers or deciding whether a string like "1" should count as an integer.

Short Answer

By the end of this page, you will understand the standard Python ways to check an object’s type: when to use isinstance(), when type() is appropriate, and how inheritance affects the result. You will also see common mistakes, practical examples, and how type checks are used in real Python code.

Concept

In Python, the canonical way to check whether an object behaves like a given type is usually isinstance(obj, SomeType).

isinstance(o, str)

This returns True if o is:

  • exactly a str, or
  • an instance of a subclass of str

That matters because Python supports inheritance. A class can extend another class, and objects of the child class should often be accepted anywhere the parent type is expected.

If you want to check whether an object is exactly one specific type and not a subclass, use:

type(o) is str

or equivalently:

type(o) == str

However, type(o) is str is typically preferred over == for exact type identity.

Why this matters

Type checks appear in real programs when:

  • validating function arguments
  • handling different input formats
  • writing APIs and libraries
  • branching logic based on object categories
  • safely processing user data

But Python generally prefers duck typing when possible: instead of asking "is this a string?", code often asks "can this object be used like a string?" Still, when you really do need a type check, isinstance() is usually the right tool.

The key rule

  • Use isinstance(obj, T) when subclasses should count.
  • Use type(obj) is T only when you need an exact type match.

Mental Model

Think of a class as a job title and inheritance as specialization.

  • str is like the job title Writer.
  • A subclass of str is like Technical Writer.

If a task says, "Anyone who is a Writer can do this," then both Writer and Technical Writer should qualify. That is what isinstance() does.

If the rule says, "Only someone with the exact title Writer, not any specialized version," then you need an exact match. That is what type(obj) is str does.

So:

  • isinstance() asks: Does this object belong to this family of types?
  • type() is asks: Is this object exactly this one type?
Take Quiz

Syntax and Examples

The two most common approaches are:

1. Check for a type or subclass with isinstance()

o = "hello"

print(isinstance(o, str))

Output:

True

This is the standard approach in Python.

2. Check for the exact type with type()

o = "hello"

print(type(o) is str)

Output:

True

This only matches if o is exactly a str.

Example with inheritance

class MyString(str):
    pass

value = MyString("hello")

print(isinstance(value, str))   # True
print(type(value) is str)       # False
print(type(value) is MyString)  # True

Explanation:

  • value is not exactly a str
  • it is a MyString
  • but MyString inherits from str, so isinstance(value, str) is True

Checking against multiple types

isinstance() can also accept a tuple of types:

value = 10

print(isinstance(value, (int, float)))

Output:

True

This is useful when several types are acceptable.

A common function example

def shout(text):
    if not isinstance(text, str):
        raise TypeError("text must be a string")
    return text.upper()

print(shout("hello"))

This validates the input before using string methods.

Step by Step Execution

Consider this example:

class Animal:
    pass

class Dog(Animal):
    pass

pet = Dog()

print(isinstance(pet, Dog))
print(isinstance(pet, Animal))
print(type(pet) is Dog)
print(type(pet) is Animal)

Here is what happens step by step:

  1. Animal is defined.
  2. Dog is defined as a subclass of Animal.
  3. pet = Dog() creates a Dog object.
  4. isinstance(pet, Dog) checks whether pet is a Dog or subclass of Dog.
    • Result: True
  5. isinstance(pet, Animal) checks whether pet is an Animal or subclass of Animal.
    • Since Dog inherits from Animal, result: True
  6. type(pet) is Dog checks the exact type.
    • pet was created from Dog, so result: True
  7. type(pet) is Animal checks whether the exact type is Animal.
    • It is not; pet is a Dog, so result: False

Output:

True
True
True
False

This example shows the difference clearly:

  • isinstance() follows inheritance
  • type() is does not

Real World Use Cases

Input validation

A function may require text input:

def save_username(name):
    if not isinstance(name, str):
        raise TypeError("name must be a string")
    # save name

Accepting several numeric types

def square(x):
    if not isinstance(x, (int, float)):
        raise TypeError("x must be numeric")
    return x * x

Handling data from APIs

When parsing JSON-like data, you may need to confirm the shape of a value:

def process_payload(data):
    if not isinstance(data, dict):
        raise TypeError("data must be a dictionary")

Working with custom class hierarchies

class Shape:
    pass

class Circle(Shape):
    pass

class Square(Shape):
    pass


def draw(shape):
    if not isinstance(shape, Shape):
        raise TypeError("Expected a Shape")

This lets Circle and Square both pass because they are both kinds of Shape.

Take Quiz

Real Codebase Usage

In real projects, developers often use type checks in controlled places rather than everywhere.

Guard clauses

A common pattern is to reject invalid input early:

def normalize_text(value):
    if not isinstance(value, str):
        raise TypeError("value must be a string")
    return value.strip().lower()

This keeps the rest of the function simpler.

Validation at module boundaries

Type checks are common where data enters the system:

  • API request handlers
  • file readers
  • command-line argument processing
  • deserialization code

Once data is validated, the rest of the code can assume correct types.

Accepting abstract parent types

Instead of checking for one exact class, code often checks for a parent type so subclasses also work:

def handle_error(err):
    if isinstance(err, Exception):
        print(f"Error: {err}")

This is flexible and works with built-in and custom exception classes.

Early return patterns

def format_label(value):
    if value is None:
        return ""
    if not isinstance(value, str):
        return str(value)
    return value.strip()

Prefer capability checks when suitable

Sometimes developers avoid strict type checks and instead rely on behavior:

def print_upper(text):
    print(text.upper())

This works for any object that provides .upper(), not just str. That style is often more Pythonic when exact type is not important.

Common Mistakes

1. Using type() when inheritance should be allowed

Broken idea:

class MyString(str):
    pass

value = MyString("hello")

print(type(value) is str)  # False

If your code should accept subclasses, use:

print(isinstance(value, str))  # True

2. Using == with type() unnecessarily

type(o) == str

This works for exact type comparison, but is better expresses that you are comparing type identity:

type(o) is str

3. Confusing type checking with conversion

value = "123"
print(isinstance(value, int))  # False

A string containing digits is still a string. If you need an integer, convert it:

number = int(value)

4. Expecting input() to return numbers automatically

age = input("Age: ")
print(isinstance(age, int))  # False

input() returns a string in Python 3. Convert it if needed:

age = int(input("Age: "))

5. Overusing type checks

Sometimes beginners write code like this:

def make_upper(value):
    if isinstance(value, str):
        return value.upper()

This returns None for non-strings and silently ignores problems. Often it is better to raise an error or rely on behavior.

Better:

def make_upper(value):
    if not isinstance(value, str):
        raise TypeError("value must be a string")
    return value.upper()

6. Forgetting that bool is a subclass of int

print(isinstance(True, int))  # True

This surprises many beginners. If you want exactly int and not bool, use:

type(True) is int   # False
type(5) is int      # True

Comparisons

ApproachWhat it checksInheritance-aware?Typical use
isinstance(obj, T)Whether obj is an instance of T or a subclass of TYesMost type checks
type(obj) is TWhether obj is exactly type TNoExact type match only
type(obj) == TAlso checks exact typeNoLess preferred than is for types

isinstance() vs type()

class Animal:
    pass

class Dog(Animal):
    pass

pet = Dog()
ExpressionResult
isinstance(pet, Dog)True
isinstance(pet, Animal)True
type(pet) is DogTrue
type(pet) is AnimalFalse

Type checking vs duck typing

StyleIdeaExample
Type checkingAsk what type the object isisinstance(x, str)
Duck typingAsk whether the object supports the needed operationx.upper()

Duck typing is often preferred in Python when behavior matters more than exact type.

Take Quiz

Cheat Sheet

Quick rules

  • Use isinstance(obj, T) for most type checks.
  • Use type(obj) is T only for exact matches.
  • isinstance() supports inheritance.
  • isinstance() can check multiple types with a tuple.

Common syntax

isinstance(obj, str)
isinstance(obj, (int, float, complex))
type(obj) is str

Examples

isinstance("hi", str)        # True
type("hi") is str            # True

class MyStr(str):
    pass

s = MyStr("hello")
isinstance(s, str)            # True
type(s) is str                # False

Important edge case

isinstance(True, int)         # True
type(True) is int             # False

When to use what

  • Want subclasses to count? Use isinstance().
  • Want the exact class only? Use type() is.
  • Want to accept several types? Use isinstance(obj, (A, B)).
  • Want to check behavior instead of class? Prefer duck typing when appropriate.

FAQ

Should I use isinstance() or type() in Python?

Usually use isinstance(). It correctly handles inheritance and is the standard choice for most checks.

How do I check if a value is a string in Python?

Use:

isinstance(value, str)

How do I check for an exact type in Python?

Use:

type(value) is str

This does not count subclasses.

Does isinstance() work with subclasses?

Yes. That is one of the main reasons it is preferred.

Can isinstance() check multiple types?

Yes:

isinstance(value, (int, float))

Why is isinstance(True, int) true?

In Python, bool is a subclass of int. If you need exact int, use type(value) is int.

Is type checking always Pythonic?

Not always. Python often prefers duck typing, where code uses an object based on what it can do rather than what exact type it is.

How do I check if an object inherits from a class?

For an object, use:

isinstance(obj, ParentClass)

If you are comparing classes themselves rather than objects, use issubclass().

Take Quiz

Mini Project

Description

Build a small validation utility that checks whether incoming values match expected Python types. This mirrors real code where data enters from user input, APIs, or configuration files and must be validated before use.

Goal

Create a function that accepts a value and verifies whether it is a string, an exact integer, or one of several allowed types.

Requirements

  • Write a function that checks whether a value is a string using isinstance().
  • Write a function that checks whether a value is exactly an int, not bool.
  • Write a function that accepts values that are either int or float.
  • Print clear results for several sample values.
  • Use both isinstance() and type() is where each one makes sense.
Take Quiz

Keep learning

Related questions

View more