Python
Programming
Object-Oriented
Class Names
Code Guide

Get fully qualified class name 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

In Python, the fully qualified class name of an object is usually the module name plus the class name. That is useful in logging, plugin systems, debugging output, and serialization metadata because it identifies the class more precisely than __name__ alone.

Basic Approach

For most objects, you can get the class from obj.__class__, then combine __module__ with __qualname__.

python
1def fully_qualified_class_name(obj):
2    cls = obj.__class__
3    return f"{cls.__module__}.{cls.__qualname__}"
4
5
6class Example:
7    pass
8
9
10value = Example()
11print(fully_qualified_class_name(value))

If Example is defined in a module named myapp.models, the result would look like:

text
myapp.models.Example

This is usually the best default because __qualname__ preserves nesting information for inner classes better than __name__.

Why __qualname__ Is Better Than __name__

__name__ gives only the immediate class name. __qualname__ includes the path inside the module for nested definitions.

python
1class Outer:
2    class Inner:
3        pass
4
5
6obj = Outer.Inner()
7print(obj.__class__.__name__)
8print(obj.__class__.__qualname__)
text
Inner
Outer.Inner

If you are generating a fully qualified identifier, __qualname__ is more informative and less likely to lose structure.

Handling Built-in Types

Built-in types still follow the same rule, but their module is often builtins.

python
print(fully_qualified_class_name(123))
print(fully_qualified_class_name("hello"))
print(fully_qualified_class_name([1, 2, 3]))
text
builtins.int
builtins.str
builtins.list

Some applications prefer to omit the builtins. prefix for readability. That is a formatting choice, not a requirement.

A Reusable Utility Function

If you want built-ins to appear without the module prefix, make that explicit in a helper:

python
1def format_class_name(obj, include_builtins=False):
2    cls = obj.__class__
3    if cls.__module__ == "builtins" and not include_builtins:
4        return cls.__qualname__
5    return f"{cls.__module__}.{cls.__qualname__}"
6
7
8print(format_class_name(10))
9print(format_class_name(10, include_builtins=True))

This keeps your logging format consistent instead of scattering ad hoc string building across the codebase.

Objects vs Classes

Be careful whether your function receives an instance or a class object. If you pass a class itself, obj.__class__ becomes type, which is not what you want.

A more defensive helper can support both:

python
1def qualified_name(value):
2    cls = value if isinstance(value, type) else value.__class__
3    return f"{cls.__module__}.{cls.__qualname__}"
4
5
6class Widget:
7    pass
8
9
10print(qualified_name(Widget))
11print(qualified_name(Widget()))

That small distinction prevents confusing output when reflective code works with a mix of instances and classes.

When a Qualified Name Is Not Enough

A fully qualified class name is useful for diagnostics, but it is not always a perfect serialization key. Classes can move between modules during refactors, and some dynamically generated classes may have names that are technically correct but awkward for storage or interoperability.

That means the pattern is excellent for logging and debugging, but more fragile as a long-term persistence format unless your application controls module stability carefully.

Logging and Plugin Use Cases

This technique is especially helpful in frameworks that load handlers, strategies, or plugins dynamically. Logging qualified_name(plugin) gives you a stable human-readable identifier that is far better than the default object representation when you are tracing configuration issues.

It is also useful during debugging sessions where inheritance chains matter. Seeing package.subpackage.CustomCache in logs immediately tells you more than simply seeing CustomCache, especially in large projects with repeated class names across modules.

Common Pitfalls

  • Using only __name__ and losing module context when different modules define classes with the same name.
  • Using __class__ on a class object and accidentally getting type instead of the intended class.
  • Preferring __name__ over __qualname__ when nested classes are possible.
  • Assuming the fully qualified name is always stable enough for long-term serialization contracts.
  • Hard-coding string formatting logic in multiple places instead of centralizing it in one helper.

Summary

  • The usual fully qualified class name is __module__ plus __qualname__.
  • '__qualname__ is more informative than __name__, especially for nested classes.'
  • Built-in types often produce names such as builtins.int.
  • If code may receive either instances or classes, handle both explicitly.
  • A small helper function keeps class-name formatting consistent across the codebase.

Course illustration
Course illustration

All Rights Reserved.