python
class to dict conversion
object serialization
python dictionaries
python programming

In python, how do I cast a class object to a dict

Master System Design with Codemia

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

Introduction

In Python, there is no single universal "cast this object to a dict" operation that works correctly for every class. The right approach depends on what kind of object you have: a normal instance, a dataclass, a nested object graph, or something that needs a custom serialized representation.

Use __dict__ or vars() for ordinary instances

For regular Python objects with writable instance attributes, the simplest answer is __dict__:

python
1class User:
2    def __init__(self, name, age):
3        self.name = name
4        self.age = age
5
6
7user = User("Ana", 32)
8print(user.__dict__)

Output:

text
{'name': 'Ana', 'age': 32}

vars(user) does the same thing:

python
print(vars(user))

This is the most direct solution when you only need the instance attributes exactly as stored on the object.

Use dataclasses.asdict for dataclasses

If the class is a dataclass, use the tool built for it:

python
1from dataclasses import dataclass, asdict
2
3
4@dataclass
5class User:
6    name: str
7    age: int
8
9
10user = User("Ana", 32)
11print(asdict(user))

This is better than reaching for __dict__ because asdict(...) also handles nested dataclasses recursively.

For example:

python
1from dataclasses import dataclass, asdict
2
3
4@dataclass
5class Address:
6    city: str
7    country: str
8
9
10@dataclass
11class User:
12    name: str
13    address: Address
14
15
16user = User("Ana", Address("Toronto", "Canada"))
17print(asdict(user))

That gives you a fully nested dictionary structure.

Add a custom to_dict method when you need control

Many real applications need more than raw attributes. Maybe you want to rename fields, omit private values, or convert dates into strings. In those cases, define the representation explicitly:

python
1from datetime import date
2
3
4class Invoice:
5    def __init__(self, invoice_id, total, issued_on):
6        self.invoice_id = invoice_id
7        self.total = total
8        self.issued_on = issued_on
9
10    def to_dict(self):
11        return {
12            "id": self.invoice_id,
13            "total": self.total,
14            "issued_on": self.issued_on.isoformat(),
15        }
16
17
18invoice = Invoice(101, 49.99, date(2026, 3, 7))
19print(invoice.to_dict())

This is often the best approach for APIs and serialization because it makes the contract explicit instead of exposing the object's internal storage mechanically.

Know the limits of __dict__

__dict__ is convenient, but it is not a universal serializer.

It has a few important limitations:

  • it only includes instance attributes stored on the object
  • it does not automatically recurse into nested custom objects
  • it may include values that are not JSON-serializable
  • it does not work the same way for classes using __slots__

For example, this object has no ordinary __dict__ storage:

python
1class Point:
2    __slots__ = ("x", "y")
3
4    def __init__(self, x, y):
5        self.x = x
6        self.y = y

In cases like that, a custom to_dict method is the safer choice.

A reusable helper for plain objects

If you want a lightweight helper for normal attribute-based objects, you can build one:

python
1def object_to_dict(obj):
2    return {
3        key: value
4        for key, value in vars(obj).items()
5        if not key.startswith("_")
6    }
7
8
9class User:
10    def __init__(self, name, age):
11        self.name = name
12        self.age = age
13        self._internal_flag = True
14
15
16print(object_to_dict(User("Ana", 32)))

This filters out private-style attributes and gives you more control than exposing __dict__ directly.

Common Pitfalls

The biggest mistake is assuming __dict__ means "safe to serialize." It only reflects the current instance attribute mapping; it does not guarantee JSON compatibility or a stable external format.

Another common issue is trying to use asdict(...) on a normal class that is not a dataclass. That function is specifically for dataclass instances.

People also forget about nested objects. A shallow dictionary can still contain custom objects that need another conversion step.

Finally, if the class uses __slots__, descriptors, or computed properties, there may not be a useful automatic mapping at all. That is usually a sign to define to_dict explicitly.

Summary

  • Use __dict__ or vars() for simple ordinary Python instances.
  • Use dataclasses.asdict(...) for dataclass objects, especially when nesting is involved.
  • Define to_dict() when you need control over names, formatting, or filtering.
  • Do not assume a raw attribute mapping is ready for JSON or API output.
  • Custom classes with __slots__ or special behavior often need an explicit conversion method.

Course illustration
Course illustration

All Rights Reserved.