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:
- Start with the object
- Get its class
- Get the class's name
Like this:
instance -> class -> class name
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
(value.__class__.__name__)
Step by Step Execution
Consider this example:
class Car:
pass
my_car = Car()
name = type(my_car).__name__
print(name)
Step by step:
- Python defines the class
Car. my_car = Car()creates an instance of that class.type(my_car)asks Python for the class ofmy_car.- Result:
<class '__main__.Car'>
- Result:
.__name__accesses the class object's name.- Result:
'Car'
- Result:
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'>
(car_class_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
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
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 :
b = Book()
((b))
((b).__name__)
Comparisons
| Approach | Returns | Best use | Notes |
|---|---|---|---|
type(obj) | Class object | General type lookup | Very common and explicit |
obj.__class__ | Class object | Direct attribute access | Usually equivalent to type(obj) |
type(obj).__name__ | String class name | Logging, debugging, messages | Most common for readable names |
obj.__class__.__name__ | String class name | Same as above | Also valid and common |
type(obj) is SomeClass |
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
inspectjust 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 SomeClasschecks exact type only.
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.
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.
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Call a Function by Name in a Python Module
Learn how to call a function by name in a Python module using strings, getattr, and safe patterns for dynamic function dispatch.
Catch Multiple Exceptions in One except Block in Python
Learn how to catch multiple exceptions in one Python except block using tuples, with examples, mistakes, and real-world usage.