Question

How to Get an Object's Class Name in Python

pythonintrospectioninstanceofpython-datamodel

Question

How can I determine the name of the class that was used to create an object instance in Python?

For example, given an object, I want to retrieve its class name as a string. I am unsure whether I should use the inspect module or access the __class__ attribute directly.

Short Answer

By the end of this page, you will understand how Python objects store type information, how to get an object's class, and how to extract the class name as a string. You will also learn when to use type(obj) versus obj.__class__, how this appears in real codebases, and which common mistakes to avoid.

Concept

In Python, every object knows what class it belongs to. That means you can ask an instance for its class and then ask that class for its name.

The most common ways to get class information are:

obj.__class__
type(obj)

Both usually give you the class object itself. Once you have the class object, you can get its name with:

obj.__class__.__name__
type(obj).__name__

If you need the full dotted path including the module, you can also use:

type(obj).__module__
type(obj).__qualname__

This matters because type information is used constantly in debugging, logging, validation, serialization, frameworks, and error messages. In most cases, you do not need the inspect module just to get a class name. inspect is more useful for deeper introspection, such as examining functions, source code, or inheritance details.

For a simple class name, direct attribute access or type() is the normal Python approach.

Mental Model

Think of every Python object as carrying an invisible label that says what kind of thing it is.

  • The object is the item.
  • The class is the blueprint used to create it.
  • The class name is the label on that blueprint.

If you pick up an object and ask, "What blueprint made you?", Python can answer with its class. Then you can ask the class, "What is your name?"

So the process is:

  1. Start with the object
  2. Get its class
  3. Get the class's name

Like this:

instance -> class -> class name
Take Quiz

Syntax and Examples

The two most common patterns are:

obj.__class__.__name__
type(obj).__name__

Example 1: Basic custom class

class Dog:
    pass

pet = Dog()

print(pet.__class__)           # <class '__main__.Dog'>
print(pet.__class__.__name__)  # Dog
print(type(pet))               # <class '__main__.Dog'>
print(type(pet).__name__)      # Dog

Explanation:

  • pet.__class__ gives the class object.
  • pet.__class__.__name__ gives the class name as a string.
  • type(pet) also gives the class object.
  • type(pet).__name__ gives the class name.

Example 2: Built-in types

value = [1, 2, 3]

print(type(value).__name__)      # list
print(value.__class__.__name__)  # list

This works for built-in types too.

Example 3: Full name with module

class Dog:
    pass

pet = Dog()

print(type(pet).__module__)   # __main__
print(type(pet).__name__)     # Dog
print(type(pet).__qualname__) # Dog

This is useful if two classes in different modules have the same name.

Step by Step Execution

Consider this example:

class Car:
    pass

my_car = Car()
name = type(my_car).__name__
print(name)

Step by step:

  1. Python defines the class Car.
  2. my_car = Car() creates an instance of that class.
  3. type(my_car) asks Python for the class of my_car.
    • Result: <class '__main__.Car'>
  4. .__name__ accesses the class object's name.
    • Result: 'Car'
  5. print(name) outputs:
Car

Here is the same idea in a more explicit form:

class Car:
    pass

my_car = Car()
car_class = type(my_car)
car_class_name = car_class.__name__

print(car_class)       # <class '__main__.Car'>
print(car_class_name)  # Car

This makes the chain easier to see:

  • my_car is the instance
  • car_class is the class object
  • car_class_name is the string name

Real World Use Cases

Getting an object's class name is useful in many practical situations.

Logging and debugging

def log_processing(obj):
    print(f"Processing object of type: {type(obj).__name__}")

This helps when debugging mixed data or framework objects.

Error messages

def expect_string(value):
    if not isinstance(value, str):
        raise TypeError(f"Expected str, got {type(value).__name__}")

This creates clearer error messages.

Serialization and event systems

Some systems store the kind of object being processed:

def serialize_record(record):
    return {
        "type": type(record).__name__,
        "data": str(record)
    }

Plugin or handler selection

def choose_handler(obj):
    return f"handle_{type(obj).__name__.lower()}"

This pattern appears in command processors, parsers, and dispatch systems.

Diagnostics in APIs and scripts

When reading JSON, files, or external input, class names can help explain what the program actually received.

Take Quiz

Real Codebase Usage

In real projects, developers usually use class names for diagnostics, validation, and readable output, not as the main way to control logic.

Common patterns

Validation with useful errors

def save_user(user):
    if user is None:
        raise ValueError("user cannot be None")

    if not hasattr(user, "id"):
        raise TypeError(f"Expected a user-like object, got {type(user).__name__}")

Guard clauses

def process(items):
    if not isinstance(items, list):
        raise TypeError(f"Expected list, got {type(items).__name__}")

    return [str(item) for item in items]

Logging framework objects

def debug_result(result):
    print(f"Result type: {type(result).__module__}.{type(result).__name__}")

A common recommendation

In production code, prefer isinstance(obj, SomeClass) when you need to check behavior or compatibility.

if isinstance(obj, dict):
    ...

This is usually better than:

if type(obj).__name__ == "dict":
    ...

Why?

  • isinstance() works with inheritance.
  • It is more explicit and reliable.
  • Comparing type names as strings is fragile.

So, use class names mostly for:

  • debugging
  • logs
  • messages
  • display
  • diagnostics

Use isinstance() for program logic.

Common Mistakes

1. Using the inspect module for a simple class name

Broken idea:

import inspect

class User:
    pass

u = User()
print(inspect.getmembers(u))

This gives far more information than needed.

Use this instead:

print(type(u).__name__)

2. Comparing class names as strings for logic

Broken example:

if type(obj).__name__ == "Animal":
    feed(obj)

Why this is risky:

  • Another class in a different module might also be named Animal
  • Subclasses may not match even when they should

Better:

if isinstance(obj, Animal):
    feed(obj)

3. Confusing the class object with the class name

class Book:
    pass

b = Book()

print(type(b))           # class object
print(type(b).__name__)  # string name
  • type(b) is not a string.
  • type(b).__name__ is the string.

4. Forgetting that __class__ returns the class, not the name

Broken expectation:

name = obj.__class__
print(name.upper())

This fails because obj.__class__ is a class object, not a string.

Correct:

name = obj.__class__.__name__
print(name.upper())

5. Using exact type checks when inheritance matters

if type(obj) is Animal:
    ...

This only matches objects whose exact type is Animal, not subclasses.

Better:

if isinstance(obj, Animal):
    ...

Comparisons

ApproachReturnsBest useNotes
type(obj)Class objectGeneral type lookupVery common and explicit
obj.__class__Class objectDirect attribute accessUsually equivalent to type(obj)
type(obj).__name__String class nameLogging, debugging, messagesMost common for readable names
obj.__class__.__name__String class nameSame as aboveAlso valid and common
type(obj) is SomeClassBooleanExact type matchDoes not include subclasses
isinstance(obj, SomeClass)BooleanType checking in logicPreferred when inheritance matters
inspect moduleIntrospection toolsAdvanced inspectionOverkill for getting class names

type(obj) vs obj.__class__

In normal code, these are effectively the same for getting an object's class.

type(obj)
obj.__class__

Both usually produce the same result.

type(...) is ... vs isinstance(...)

class Animal:
    pass

class Dog(Animal):
    pass

pet = Dog()

print(type(pet) is Animal)      # False
print(isinstance(pet, Animal))  # True

Use isinstance() when subclass relationships should count.

Take Quiz

Cheat Sheet

# Get the class object
obj.__class__
type(obj)

# Get the class name as a string
obj.__class__.__name__
type(obj).__name__

# Get module + class information
type(obj).__module__
type(obj).__qualname__

Quick rules

  • Use type(obj).__name__ to get a readable class name.
  • Use isinstance(obj, MyClass) for type-based logic.
  • Do not use inspect just to get a class name.
  • Do not compare class-name strings when class objects or isinstance() would work better.

Examples

class User:
    pass

u = User()

print(type(u))           # <class '__main__.User'>
print(type(u).__name__)  # User

Edge cases

  • Two different classes can have the same __name__ if they come from different modules.
  • type(obj) is SomeClass checks exact type only.
  • isinstance(obj, SomeClass) includes subclasses.

FAQ

How do I get the class name of an object in Python?

Use:

type(obj).__name__

This returns the class name as a string.

Is obj.__class__.__name__ valid in Python?

Yes. It is a normal and valid way to get the class name.

Should I use inspect to get an object's class name?

Usually no. inspect is unnecessary for this task. type(obj).__name__ or obj.__class__.__name__ is enough.

What is the difference between type(obj) and obj.__class__?

Both usually return the object's class. For this use case, either is fine.

How do I get the full class path, not just the class name?

Use module and qualified name:

full_name = f"{type(obj).__module__}.{type(obj).__qualname__}"

Should I compare class names as strings?

Usually no. For program logic, prefer isinstance() or direct class comparisons.

Why does type(obj) is MyClass fail for subclasses?

Because it checks only the exact type. If obj is an instance of a subclass, use isinstance(obj, MyClass) instead.

Take Quiz

Mini Project

Description

Build a small debugging helper that reports what kind of values a program receives. This demonstrates how to get class names from object instances and how that information can make logs and error messages easier to understand.

Goal

Create a function that prints each value along with its class name and module information.

Requirements

  • Define at least one custom class.
  • Create a mixed list containing built-in values and an instance of your custom class.
  • Write a function that prints the value, its class name, and its module.
  • Use type(obj).__name__ in the solution.
  • Show the function working on every item in the list.
Take Quiz

Keep learning

Related questions

View more