In the Python json library, what is the primary difference between the json.dump() function and the
The "s" in dumps and loads stands for String.
Memory vs. Storage:
json.dumps(obj): Useful when you want to send JSON over a network or store it in a database as a string.
json.dump(obj, file_ptr): Useful when you want to save your data directly into a .json file on your hard drive.
Mnemonic: Just remember: dump (to a file) vs. dump-S (to a String).
When converting a Python dictionary to JSON, how is a Python Tuple (e.g., (1, 2, 3)) represented in the resulting JSON string?
JSON is a language-independent format, and it does not have a "Tuple" type. It only has Arrays.
Type Translation:
Python list → JSON array
Python tuple → JSON array
Python dict → JSON object
Note: This means that if you serialize a tuple and then deserialize it back into Python, it will come back as a list, not a tuple!
Which of the following code snippets correctly reads a JSON file named config.json and loads its content into a Python variable?
To read from a file, you must first open the file to create a file-like object, and then pass that object to json.load().
Common Pitfalls:
Using json.loads() with a filename string will fail because loads expects the actual JSON content, not a path.
Option 4 is the safest method because the with statement ensures the file is closed immediately after the data is loaded.
How are the Python values True, False, and None represented in a JSON string?
JSON follows JavaScript's naming conventions for its primitive values.
Python
JSON
True
true
False
false
None
null
What is a strict requirement for "Keys" in a JSON object (the equivalent of Python dictionary keys)?
This is a major difference between Python dictionaries and JSON objects.
Key Constraints:
In Python, a dictionary key can be any immutable type (int, float, string, tuple).
In JSON, every key must be a string.
If you have a Python dict {101: "Active"} and you dump it to JSON, it will become {"101": "Active"}. When you load it back, your integer key 101 will have become the string "101"!
You are generating a JSON configuration file that needs to be easily readable by humans. Which parameter in json.dumps() should you use to add line breaks and consistent spacing?
By default, Python's json library produces "compact" JSON to save space during transmission. While efficient for machines, it is a single, long line of text that is hard for humans to read.
The Indent Parameter:
Setting indent to a non-negative integer or a string (like "\t") enables pretty-printing. It adds newlines and the specified number of spaces per level of nesting.
You have a dictionary containing emojis or non-English characters (e.g., {"greet": "Héllö"}). When you run json.dumps(), the output shows {"greet": "H\u00e9ll\u00f6"}. How can you ensure the JSON output displays the actual characters?
By default, json.dumps() escapes all non-ASCII characters by turning them into \uXXXX sequences. This ensures the output can be safely transmitted over older systems that only support 7-bit ASCII.
If you set ensure_ascii=False, Python will output the actual Unicode characters. This makes the JSON much easier to read for international users and supports emojis natively.
Why would you set sort_keys=True when serializing a Python dictionary to JSON?
In modern Python (3.7+), dictionaries maintain their insertion order. However, if two different scripts build the same dictionary in a different order, their resulting JSON strings will not match byte-for-byte.
Deterministic Output:
Setting sort_keys=True forces the JSON object keys to be output in alphabetical order. This is highly recommended when you are saving configuration files to Git, as it prevents "noisy" diffs where the data is the same but the order changed.
The separators parameter takes a tuple: (item_separator, key_separator).
Customizing Space:
The default is (", ", ": "), which adds spaces after commas and colons for readability.
By using (",", "="), you removed the spaces and changed the colon to an equals sign.
Warning: Changing the key separator to "=" produces Invalid JSON. Most other programs will not be able to read this file. This parameter is usually only used to remove spaces (",", ":") to create the most compact output possible for network efficiency.
Which Python data type will cause a TypeError if you attempt to serialize it using json.dumps() without custom configuration?
While Python has many built-in types, the JSON Standard is very limited. It only supports: Strings, Numbers, Objects (dicts), Arrays (lists), Booleans, and Null.
The Set Problem:
A Python set has no direct equivalent in JSON. Unlike a tuple (which Python can lazily convert to an array), the json library will not assume a set should be an array because sets are unordered and unique. You must convert a set to a list manually before dumping.
You are trying to serialize a dictionary containing a datetime object. Since JSON doesn't support dates, you decide to use the default parameter of json.dumps(). What should the function passed to default do?
The default parameter is a fallback function. When the JSON encoder encounters an object it doesn't recognize (like a datetime or a custom User class), it calls this function.
The Workflow:
The function receives the "unserializable" object. Your job is to convert it into something JSON does understand, such as an ISO-formatted string.
import json
from datetime import datetime
def my_converter(obj):
if isinstance(obj, datetime):
return obj.isoformat() # Returns a string
raise TypeError("Type not serializable")
json.dumps({"now": datetime.now()}, default=my_converter)
If you want to reuse your custom serialization logic across multiple parts of a large application, what is the most organized approach according to the json library documentation?
Subclassing JSONEncoder is the "Enterprise" way to handle custom types. It allows you to bundle all your conversion rules into one object.
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, MyCustomClass):
return obj.__dict__
return super().default(obj)
# Usage:
json.dumps(data, cls=MyEncoder)
Note: Calling super().default(obj) at the end is vital—it allows the standard library to raise the proper TypeError if the object is truly unknown.
You have a JSON string representing a User: {"name": "Alice", "id": 42}. When you call json.loads(), you want it to return an actual instance of your User class instead of a dictionary. Which parameter facilitates this?
The object_hook is a powerful feature for Data Hydration (turning raw data back into logic-rich objects).
How it works:
Every time the decoder creates a dictionary from the JSON string, it passes that dictionary to your object_hook function before returning it. If your function returns a class instance, that instance replaces the dictionary in the final output.
def make_user(d):
if "name" in d and "id" in d:
return User(d["name"], d["id"])
return d
data = json.loads(json_str, object_hook=make_user)
# data is now a User object!
JSON represents all numbers as floats. If you are dealing with financial data where precision is critical, what is the safest way to load a JSON string like {"price": 19.99} into Python?
Standard floats in Python (and JSON) suffer from binary rounding errors (e.g., 0.1 + 0.2 != 0.3). This is unacceptable for banking or scientific apps.
By passing decimal.Decimal to the parse_float parameter, you tell the decoder to bypass the standard float conversion and create high-precision Decimal objects directly from the raw string in the JSON.
You are reading a file that contains multiple JSON objects concatenated together (e.g., {"id": 1}{"id": 2}). Standard json.load() will raise a JSONDecodeError. What tool should you use to handle this?
This is a common issue with "streaming" JSON data or log files. raw_decode allows you to decode an object and tells you exactly where that object ended in the string.
You can then use that index to start decoding the next object from the remaining string. This is the only way to parse a file that isn't wrapped in a single top-level array or object.
What is the outcome of executing the following code, and why?
import json
a = {}
b = {'ref': a}
a['ref'] = b
json.dumps(a)
JSON is a tree structure, not a graph. It cannot represent an object that contains itself (directly or indirectly).
The 'check_circular' flag:
By default, json.dumps() has check_circular=True. It tracks every object it visits; if it sees the same object twice in the same branch, it raises a ValueError to prevent an infinite loop.
If you were to set check_circular=False, the code would eventually result in a RecursionError as the stack overflows.
In Python, float('nan') is a valid number. However, the JSON specification (RFC 8259) does not officially support NaN or Infinity. How does the Python json library handle this by default?
Python prioritizes utility over strict RFC compliance by default. It uses the allow_nan=True parameter.
The Compatibility Trap:
While json.loads() in Python can read back these values, most other languages (like JavaScript or Java) will crash because NaN (unquoted) is invalid JSON. If you are sending data to a web browser, you should set allow_nan=False to force a ValueError in Python before sending bad data.
Consider a JSON string that is nested 2,000 levels deep: [[[[...]]]]. What is the primary risk when calling json.loads() on this string?
The standard json decoder is a recursive descent parser. This means every new level of [ or { creates a new frame on the Python call stack.
Most Python installations have a limit of 1,000. For deeply nested malicious JSON (a "JSON Bomb"), this can crash your application. In production environments, it is often necessary to use sys.setrecursionlimit() or a non-recursive parser like ijson for untrusted data.
You need to parse a JSON file where all integers should be loaded as str to prevent precision loss (even though they aren't floats). Which implementation of a custom JSONDecoder correctly achieves this?
This is the most granular way to control the json library's internals.
The JSONDecoder constructor accepts several parse_xxx arguments. By passing str to parse_int, the low-level scanner will pass the raw string of digits directly to the str() constructor instead of int(), allowing you to handle extremely large numbers that might otherwise exceed Python's integer-to-string conversion limits or specific data requirements.
In Python, multiple variables can point to the same object in memory. Study the code below and determine what happens to the relationship between list_a and list_b after a round-trip through JSON serialization.
import json
shared_resource = ["connection_pool", "active"]
data = {
"module_1": shared_resource,
"module_2": shared_resource
}
# Serialize and Deserialize
serialized_data = json.dumps(data)
new_data = json.loads(serialized_data)
# Modify the resource in module_1
new_data["module_1"][1] = "inactive"
print(new_data["module_2"][1])
This is a fundamental limitation of the JSON format. JSON is a Tree-based format, meaning every piece of data is treated as an independent branch.
The "Identity" Problem:
In the original Python dictionary, module_1 and module_2 both pointed to the exact same memory address of shared_resource. If you changed one, the other would reflect it.
When you convert to JSON, the library simply sees two identical lists. It writes the data twice: {"module_1": ["connection_pool", "active"], "module_2": ["connection_pool", "active"]}.
When you load it back, Python creates two entirely separate list objects. The "link" between them is permanently broken. This is why for complex object graphs where identity matters, pickle or a graph-database approach is required.
Quick Recap of Python Working with JSON Concepts
If you are not clear on the concepts of Working with JSON, you can quickly review them here before practicing the exercises. This recap highlights the essential points and logic to help you solve problems confidently.
Working with JSON — Definition, Mechanics, and Usage
JSON (JavaScript Object Notation) is a lightweight, text-based data format used universally for data exchange. In Python, the json module translates between Python objects (dictionaries, lists) and JSON strings or files. This is essential for web APIs, configuration files, and persistent data storage.
Because JSON structure closely mirrors Python's native dictionary and list types, it is the most common format for passing data between a Python backend and a web frontend or external service.
Why Use JSON — Key Benefits
JSON is preferred over other formats like XML or Pickle because it is easier to read, faster to parse, and supported by every modern programming language.
Benefit
Detailed Explanation
Language Agnostic
JSON is supported by virtually every language, enabling Python to communicate with JavaScript, Java, or C++.
Provides a simple way to save complex data structures to a .json file and reload them later without losing structure.
Human-Readable
Unlike binary formats, JSON is plain text, making it easy for developers to debug and edit configuration files.
Serialization: Python to JSON (dump and dumps)
Serialization is the process of converting a Python object into a JSON-formatted string. This is necessary when you want to send data over a network or save it to a disk.
json.dumps(): The "s" stands for string. It returns a JSON-formatted string.
json.dump(): Used for files. It writes JSON data directly to a file stream.
import json
data = {
"user": "Alice",
"score": 95,
"verified": True,
"tags": ["python", "dev"]
}
# 1. Serialization to String
json_string = json.dumps(data)
print(f"Serialized String: {json_string}")
# 2. Serialization to File (Handling .json Files)
with open("profile.json", "w", encoding='utf-8') as f:
json.dump(data, f)
Deserialization: JSON to Python (load and loads)
Deserialization is the inverse process: transforming a JSON string or file back into a Pythonic data structure (usually a dictionary or list) so your code can manipulate the data.
json.loads(): Parses a JSON-formatted string.
json.load(): Parses a JSON file from a file stream.
import json
# 1. Deserialization from String
json_input = '{"status": "active", "code": 200, "data": null}'
python_dict = json.loads(json_input)
# JSON 'null' automatically becomes Python 'None'
print(f"Status: {python_dict['status']}, Data: {python_dict['data']}")
# 2. Deserialization from File
with open("profile.json", "r", encoding='utf-8') as f:
loaded_data = json.load(f)
print(f"Loaded User from File: {loaded_data['user']}")
Pretty Printing and Sorting
Raw JSON is often a single line of text, which is efficient for machines but difficult for humans to read. Python provides parameters to format the output for better readability in logs or configuration files.
import json
raw_data = {"c": 3, "a": 1, "b": 2, "nested": {"id": 10, "status": "ok"}}
# indent: Adds spaces/formatting for a visual hierarchy
# sort_keys: Alphabetizes keys to ensure consistent output
pretty_json = json.dumps(raw_data, indent=4, sort_keys=True)
print(pretty_json)
# Resulting output is structured and easy to audit
Handling JSON Errors (Robust Code)
When working with external APIs, the data you receive might be malformed or truncated. If you do not handle JSONDecodeError, your entire application will crash when it encounters an invalid string.
from json import JSONDecodeError
import json
invalid_json = '{"name": "Bob", "age": 30' # Missing closing brace
try:
data = json.loads(invalid_json)
except JSONDecodeError as e:
print(f"Critical Error: Failed to parse JSON.")
print(f"Error Details: {e.msg} at line {e.lineno}, column {e.colno}")
Custom Encoders: Handling Sets and Classes
By default, the json module cannot serialize types like set, complex, or Custom Class Instances. You must provide a default function to convert these into JSON-supported types (like lists or dictionaries).
class Task:
def __init__(self, title, status):
self.title = title
self.status = status
def my_encoder(obj):
# Check if the object is our custom class
if isinstance(obj, Task):
return obj.__dict__ # Return the internal dictionary of the class
# Handle sets (JSON doesn't have a 'set' type, only 'array')
if isinstance(obj, set):
return list(obj)
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
# Usage with the 'default' parameter
task_json = json.dumps(Task("Write Code", "Done"), default=my_encoder)
print(task_json)
Best Practices With JSON
Always Use UTF-8: When opening files for JSON, always specify encoding='utf-8' to ensure compatibility across different operating systems.
Validate External Data: Never assume an API response is valid JSON. Always wrap loads() in a try...except block.
Security First: Avoid serializing dictionaries that contain sensitive data like passwords, private keys, or internal system paths.
Compact for Network: Only use indent for local files or debugging. For network transmission, omit indentation to save bandwidth and improve performance.
Summary: Key Points
Serialization: Use dumps (string) and dump (file) to move from Python to JSON.
Deserialization: Use loads (string) and load (file) to move from JSON to Python.
Data Mapping: JSON null → Python None; true/false → True/False.
Readability: Use indent and sort_keys for human-friendly debugging.
Extensibility: Use the default argument in dumps to handle non-serializable types like custom classes.
Test Your Python Working with JSON Knowledge
Practicing Python Working with JSON? Don’t forget to test yourself later in our Python Quiz.
About This Exercise: Working with JSON in Python
In the modern era of web development and data science, JSON (JavaScript Object Notation) is the undisputed language of data exchange. At Solviyo, we know that being a great Python developer means more than just knowing basic syntax; it’s about knowing how to talk to other systems. Whether you are consuming a REST API or saving user settings to a configuration file, you need to be comfortable moving between Python dictionaries and JSON strings. We’ve designed these Python exercises to help you master the json module, covering everything from basic parsing to advanced custom serialization.
We’re moving beyond simple data types. These exercises will push you to handle complex nested structures and common pitfalls like date formatting and non-serializable objects. You’ll tackle MCQs and coding practice that explain the difference between json.load() and json.loads(), ensuring you never get confused by file streams and strings again. By the end of this section, you'll be able to manipulate data pipelines with confidence and precision.
What You Will Learn
This section is designed to turn data manipulation into a seamless habit. Through our structured Python exercises with answers, we’ll explore:
Serialization: Using json.dump() and json.dumps() to convert Python objects into JSON-ready strings.
Deserialization: Mastering json.load() and json.loads() to transform JSON back into Pythonic data structures.
Handling Files: Working directly with .json files to read and write persistent data.
Pretty Printing: Using indentation and sorting keys to create human-readable JSON outputs.
Custom Encoders: Learning how to handle types that JSON doesn't support by default, like sets or custom class instances.
Why This Topic Matters
Why do we care about JSON? Because it is everywhere. Almost every web API in existence uses JSON to communicate. If your code can't speak JSON, it’s isolated. Mastering this topic allows your Python scripts to interact with frontend frameworks, mobile apps, and cloud services. It’s the primary way we bridge the gap between different programming languages and platforms.
From a professional perspective, efficient JSON handling is a major part of building scalable backends. Understanding how to serialize data correctly prevents bugs during data transmission and ensures your application can handle the high-speed demands of modern traffic. Whether you're a data engineer or a full-stack dev, these skills are non-negotiable for building interconnected software systems.
Start Practicing
Ready to master the web’s favorite data format? Every one of our Python exercises comes with detailed explanations and answers to help you bridge the gap between theory and code. We break down the mapping between Python and JSON types so you can write cleaner, more efficient parsers. If you need a quick refresh on the difference between a string and a stream, check out our "Quick Recap" section before you dive in. Let’s see how you handle real-world data structures.
Need a Quick Refresher?
Jump back to the Python Cheat Sheet to review concepts before solving more challenges.