Question
How can a Python class instance be made JSON serializable?
class FileItem:
def __init__(self, fname):
self.fname = fname
Attempting to serialize an instance raises an error:
import json
x = FileItem("/foo/bar")
json.dumps(x)
# TypeError: Object of type FileItem is not JSON serializable
What is the correct way to convert this class instance to JSON?
Short Answer
By the end of this page, you will understand why json.dumps() cannot serialize arbitrary Python objects, how to convert an object into JSON-compatible data, and when to use to_dict(), the default argument, or a custom JSONEncoder.
Concept
JSON is a text format with a small set of supported value types:
- object: Python
dict - array: Python
listortuple - string: Python
str - number: Python
intorfloat - boolean: Python
TrueandFalse - null: Python
None
A FileItem instance is a custom Python object, not one of those JSON types. Although its data is stored in x.fname, the JSON module does not automatically know which attributes should be included, renamed, excluded, or converted.
The usual solution is to explicitly convert the object into a JSON-compatible dictionary first. This makes the serialization format clear and keeps your class in control of its public data format.
import json
json_data = json.dumps({"fname": "/foo/bar"})
print(json_data)
# {"fname": "/foo/bar"}
In real programs, explicit conversion matters because objects often contain values that JSON cannot represent directly, such as datetime objects, objects, database connections, functions, or other custom instances.
Mental Model
Think of JSON as a shipping form that accepts only a few standard field types: text, numbers, yes/no values, empty values, lists, and labeled groups of fields.
A Python class instance is like a custom item in a box. The shipping form cannot inspect it and guess what belongs on the form. A to_dict() method is the packing instruction: it tells Python exactly which parts of the object should be written as standard JSON data.
Syntax and Examples
The clearest pattern is to add a method that returns a dictionary containing only JSON-compatible values.
import json
class FileItem:
def __init__(self, fname):
self.fname = fname
def to_dict(self):
return {
"fname": self.fname
}
item = FileItem("/foo/bar")
json_text = json.dumps(item.to_dict())
print(json_text)
# {"fname": "/foo/bar"}
item.to_dict() produces this ordinary dictionary:
{"fname": "/foo/bar"}
Since dictionaries and strings are supported by JSON, json.dumps() can serialize it.
For this very simple class, item.__dict__ also works:
json_text = json.dumps(item.__dict__)
However, prefer to_dict() in most applications. It gives you control over the JSON structure and avoids exposing every internal attribute automatically.
Step by Step Execution
Consider this code:
import json
class FileItem:
def __init__(self, fname):
self.fname = fname
def to_dict(self):
return {"fname": self.fname}
item = FileItem("/foo/bar")
data = item.to_dict()
json_text = json.dumps(data)
Step by step:
FileItem("/foo/bar")creates a custom object nameditem.self.fname = fnamestores the string"/foo/bar"on that object.item.to_dict()creates{"fname": "/foo/bar"}.- The dictionary contains only JSON-supported values: a string key and a string value.
json.dumps(data)converts the dictionary into the JSON text'{"fname": "/foo/bar"}'.
If you instead call json.dumps(item), the encoder sees a FileItem object and raises because no conversion rule was supplied.
Real World Use Cases
Custom-object serialization is common whenever Python data must cross a boundary:
- API responses: Convert domain objects such as users, orders, or files into JSON response bodies.
- Configuration files: Store application settings or saved preferences as JSON.
- Caching: Serialize simple data representations before writing them to a cache.
- Message queues: Send event payloads, such as
file_uploaded, to another service. - Logging and auditing: Record structured details in JSON logs.
- Command-line tools: Export results in a portable format that other tools can read.
For example, an API may return a file record as:
{
"name": "report.pdf",
"path": "/uploads/report.pdf",
"size_bytes": 2048
}
The application may use a FileItem class internally, but it sends a dictionary-shaped JSON representation to clients.
Real Codebase Usage
In production code, developers usually keep JSON conversion explicit and close to the data model.
Use to_dict() for a stable public representation
class FileItem:
def __init__(self, fname, is_public):
self.fname = fname
self.is_public = is_public
self._cache_key = "internal-only"
def to_dict(self):
return {
"filename": self.fname,
"public": self.is_public
}
This pattern can rename fields and prevent _cache_key from leaking into an API response.
Use default= when serializing collections
If a list or dictionary may contain custom objects, pass a conversion function to json.dumps():
import json
class FileItem:
def __init__():
.fname = fname
():
{: .fname}
():
(value, FileItem):
value.to_dict()
TypeError()
items = [FileItem(), FileItem()]
(json.dumps(items, default=serialize_object))
Common Mistakes
Passing the instance directly
This fails because FileItem is not a built-in JSON type.
json.dumps(FileItem("/foo/bar")) # TypeError
Convert it with to_dict() or provide a default function.
Assuming __dict__ is always the best format
json.dumps(item.__dict__)
This can be convenient for temporary scripts, but it may expose internal fields or stop working as expected when the class changes. Prefer an explicit to_dict() method for data that other systems consume.
Returning another unsupported object from to_dict()
The dictionary itself must contain JSON-compatible values.
from pathlib import Path
class FileItem:
def __init__(self, fname):
self.fname = Path(fname)
def to_dict(self):
{: .fname}
Comparisons
| Approach | Best use | Advantage | Limitation |
|---|---|---|---|
json.dumps(item.to_dict()) | Most classes and APIs | Explicit, readable, easy to test | Must call to_dict() before dumping |
json.dumps(item.__dict__) | Quick prototypes with simple objects | Very short | Exposes all instance attributes and offers little control |
json.dumps(data, default=func) | Nested lists or dictionaries containing objects | Handles unsupported values while traversing data | The conversion policy can be less visible at the call site |
json.dumps(data, cls=Encoder) | Shared serialization rules across a project | Reusable encoder class | More code for simple cases |
Cheat Sheet
import json
class FileItem:
def __init__(self, fname):
self.fname = fname
def to_dict(self):
return {"fname": self.fname}
item = FileItem("/foo/bar")
# Object -> JSON string
text = json.dumps(item.to_dict())
# JSON string -> Python dictionary
data = json.loads(text)
# Dictionary -> object
restored = FileItem(**data)
Rules:
json.dumps()returns a JSON string.json.loads()accepts a JSON string.- JSON supports dictionaries, lists, strings, numbers, booleans, and
None. - Convert custom objects and values such as
Path,datetime, andsetto supported values first. - Prefer
to_dict()when you need a deliberate, stable JSON format. - Use
default=...orcls=...when unsupported objects appear inside nested data.
FAQ
Why is my Python class not JSON serializable?
Python's JSON encoder only knows the standard JSON value types. A custom class instance needs an explicit conversion rule.
Is __dict__ JSON serializable?
Often, yes: obj.__dict__ is a dictionary of instance attributes. It works only if every attribute value is also JSON serializable. It is less safe than an explicit to_dict() method.
Should I use to_json() or to_dict()?
Use to_dict() when possible, then call json.dumps() separately. A dictionary is useful beyond JSON, such as testing, validation, and API frameworks.
How do I serialize a list of class instances?
Convert each item with a list comprehension:
json.dumps([item.to_dict() for item in items])
Or supply a default conversion function to json.dumps().
Can json.loads() recreate my class automatically?
No. It returns standard Python values such as dictionaries and lists. Create the object yourself, for example FileItem(**data).
Mini Project
Description
Build a small file catalog exporter. The program stores file metadata in FileItem objects, converts each object to a safe dictionary, and exports the catalog as formatted JSON. This is similar to preparing data for an API response or a JSON report.
Goal
Create a JSON string containing a list of file records without passing custom class instances directly to json.dumps().
Requirements
Create a FileItem class with fname and size_bytes attributes.
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.
Add Rows to a Pandas DataFrame in Python
Learn how to add rows to a Pandas DataFrame, why repeated row appends are slow, and when to use loc, concat, or record lists.
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.