SECTION 1
Historical Context & Motivation
Whenever two programs need to share information—like a weather app pulling data from a server, or a video game saving your progress—they need an agreed-upon format for organizing that data. In the early days of the web, developers used a verbose format called XML (Extensible Markup Language), which worked but was bulky and hard to read. Developers wanted something lighter, easier for humans to scan, and simpler for machines to process.
That need led to JSON (JavaScript Object Notation), a lightweight text format originally derived from JavaScript syntax but now used across virtually every programming language. JSON struck the perfect balance: it is compact enough for network transmission and readable enough for a developer to debug at a glance.
1999 • JSON Conceived
2002 • json.org Launched
2006 • Python Adds json Module
json module, making JSON reading and writing a one-import operation for Python programmers.2013 • ECMA-404 Standard
2020s • Universal Adoption
The central question this lesson addresses is: how do you take a Python data structure—like a dictionary or a list—turn it into a JSON text file, and then read it back into Python later? Understanding this workflow is essential for building any program that saves settings, communicates with web services, or processes datasets.
SECTION 2
Core Principles & Definitions
Before writing any code, you need to understand what JSON actually looks like and how its pieces map onto Python data types. JSON is built from just two container structures—objects and arrays—plus a handful of simple value types. Once you see the mapping, reading and writing JSON in Python feels natural.
JSON Object → Python dict
{ }. Keys must be strings. In Python, this becomes a dict.JSON Array → Python list
[ ]. In Python, this maps to a list.Primitive Values
true / false), and null. Python converts these to str, int/float, bool, and None.Serialization & Deserialization
The json Module
json module provides four key functions: json.dump(), json.dumps(), json.load(), and json.loads(). The "s" stands for "string."KEY TAKEAWAY
json module is the translator that packs Python objects into labeled JSON boxes (serialization) and unpacks JSON boxes back into Python objects (deserialization).SECTION 3
Visual Explanation — JSON Structure Map
json.load() reads JSON into Python, and json.dump() writes Python out as JSON.Notice that JSON booleans use lowercase (true and false) while Python capitalizes them (True and False). Similarly, JSON uses null where Python uses None. The json module handles these translations automatically, so you don't have to worry about converting them yourself.
SECTION 4
How the json Module Works
Python's json module gives you four main functions, and understanding when to use each one is the key to mastering JSON I/O. Two of them work with files and two work with strings. The naming convention makes this easy to remember: the functions ending in "s" (for "string") work with strings in memory, while the functions without "s" work directly with file objects.
Writing JSON
WRITE TO FILE
data — the Python dict or list to serialize. file_object — an open file in write mode. indent — optional parameter that pretty-prints the JSON with the given number of spaces.
WRITE TO STRING
Returns a str containing the JSON text. Useful when you want to inspect the JSON before saving, or send it over a network.
Reading JSON
READ FROM FILE
Reads the entire file, parses the JSON text, and returns the corresponding Python object (usually a dict or list).
READ FROM STRING
Parses a JSON-formatted str and returns the corresponding Python object. Commonly used when receiving JSON from a web API.
Memory Trick
dumps and loads stands for string. No "s" = works with a file. Has an "s" = works with a string.SECTION 5
Anatomy of a JSON File
Let's look at a realistic JSON file and break down every element. Imagine you are building a simple contact book application. Each contact has a name, age, email, a list of hobbies, and an indicator of whether they are active. Below is a JSON file that stores one such contact along with the application's metadata.
There are a few rules to remember about JSON syntax. First, all keys and string values must be enclosed in double quotes—single quotes are not valid in JSON (even though Python allows them). Second, trailing commas after the last item in an object or array are not allowed, which is a common source of errors when hand-editing JSON files. Third, JSON does not support comments, so you cannot add # or // annotations inside a JSON file.
SECTION 6
Worked Example — Save and Load a Student Record
Let's walk through a complete example where we create a Python dictionary representing a student, write it to a JSON file, and then read it back into Python.
Writing and Reading a Student Record with JSON
- 1
Step 1 — Import the json module
At the top of your Python script, import the built-injsonmodule. No installation is needed—it comes with every Python distribution.import jsonThejsonmodule is now available for use. - 2
Step 2 — Create the Python data structure
Build a dictionary with the student's information. This dict can contain nested lists and other data types.student = {"name": "Jordan", "grade": 11, "gpa": 3.85, "courses": ["Python", "Algebra 2", "English"], "honor_roll": True}A dict with strings, an int, a float, a list, and a bool. - 3
Step 3 — Write the dict to a JSON file
Open a file in write mode ("w") and usejson.dump()to serialize the dict into that file. Theindent=4parameter makes the output human-readable.with open("student.json", "w") as f: json.dump(student, f, indent=4)A file namedstudent.jsonis created with pretty-printed JSON content. - 4
Step 4 — Read the JSON file back into Python
Open the same file in read mode ("r") and usejson.load()to deserialize the JSON text back into a Python dictionary.with open("student.json", "r") as f: loaded = json.load(f)The variableloadedis now a Python dict identical to the originalstudentdict. - 5
Step 5 — Access data from the loaded dict
You can now use the loaded data just like any Python dictionary. Access individual values by key, iterate over lists, or check boolean flags.print(loaded["name"]) # Jordan print(loaded["courses"][0]) # Python print(loaded["honor_roll"]) # TrueThe program prints: Jordan, Python, True — confirming the data round-tripped successfully.
SECTION 7
Strengths, Limitations & Common Pitfalls
JSON is incredibly popular, but it is not perfect for every situation. Knowing its strengths and limitations will help you choose the right tool for each project and avoid frustrating bugs.
| Aspect | Strengths ✅ | Limitations ⚠️ |
|---|---|---|
| Readability | Human-readable text format; easy to inspect and debug in any text editor. | Large files can become hard to navigate without specialized tools. |
| Data Types | Covers the most common types: strings, numbers, booleans, null, arrays, and objects. | Cannot store Python-specific types like tuples, sets, datetime objects, or custom classes without extra conversion. |
| Cross-Language | Nearly every programming language has a JSON library, making it ideal for data exchange. | Slight differences in number precision between languages can cause rare edge-case bugs. |
| File Size | Much more compact than XML for the same data. | Binary formats like Protocol Buffers or MessagePack are smaller and faster for huge datasets. |
| Comments | The strict format avoids ambiguity; parsers are fast and simple. | No support for comments — you cannot annotate a JSON file with explanations. |
JSON strengths vs. limitations for typical programming tasks
WHEN TO USE JSON
SECTION 8
Connection to Advanced Topics
The JSON skills you are building now form the foundation for many advanced topics in software development. As you progress, you will encounter more complex scenarios that build directly on json.load() and json.dump().
| What You Learn Now | Where It Leads |
|---|---|
| Reading/writing JSON files locally | Consuming REST APIs over the internet (e.g., weather data, social media APIs) using the requests library |
| Simple dicts and lists in JSON | Working with deeply nested JSON from real-world APIs and databases like MongoDB |
Using indent for pretty-printing | Custom serializers using json.JSONEncoder to handle datetime objects, sets, and custom classes |
| Basic type mapping (dict, list, str, int) | Schema validation with libraries like jsonschema to ensure data conforms to an expected structure |
How basic JSON I/O skills connect to advanced programming topics
One especially exciting next step is learning to interact with web APIs. When you send a request to a server—say, asking for today's weather in your city—the server typically responds with a JSON string. You already know how to parse that string with json.loads() and extract the data you need. The skills from this lesson transfer directly.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
json.dump() and json.dumps()? When would you use each one?Show answer
json.dump() writes JSON data directly to a file object, while json.dumps() returns the JSON as a Python string. You would use json.dump() when you want to save data to a file on disk, for example saving game progress. You would use json.dumps() when you need the JSON as a string in memory, such as when printing it for debugging or preparing to send it over a network. The 's' at the end is a reminder that the function works with strings rather than files.Question 2: BASIC CALCULATION
pet = {"name": "Luna", "species": "cat", "age": 3, "vaccinated": True}, write the Python code to save this dictionary to a file called pet.json with an indentation of 2 spaces.Show answer
import json
pet = {"name": "Luna", "species": "cat", "age": 3, "vaccinated": True}
with open("pet.json", "w") as f:
json.dump(pet, f, indent=2)
This opens pet.json in write mode, then json.dump() serializes the pet dictionary into the file. The indent=2 parameter makes the JSON output nicely formatted with 2-space indentation. Python's True is automatically converted to JSON's lowercase true.Question 3: INTERMEDIATE
scores.json that contains: {"math": 92, "science": 88, "english": 95}. Write a Python program that reads this file, adds a new key "history": 90, and then writes the updated dictionary back to the same file.Show answer
import json
with open("scores.json", "r") as f:
scores = json.load(f)
scores["history"] = 90
with open("scores.json", "w") as f:
json.dump(scores, f, indent=4)
First, we open the file in read mode and use json.load() to parse the JSON into a Python dict. Then we add the new key-value pair using standard dict syntax. Finally, we reopen the file in write mode (which overwrites the old content) and dump the updated dict back. This read-modify-write pattern is extremely common when working with JSON configuration or data files.Question 4: APPLIED
"task", "done", and "priority"), saves the list to todos.json, loads it back, and prints only the tasks that are not yet done.Show answer
import json
todos = [
{"task": "Study for quiz", "done": False, "priority": 1},
{"task": "Walk the dog", "done": True, "priority": 2},
{"task": "Finish essay", "done": False, "priority": 1}
]
with open("todos.json", "w") as f:
json.dump(todos, f, indent=4)
with open("todos.json", "r") as f:
loaded_todos = json.load(f)
for item in loaded_todos:
if not item["done"]:
print(item["task"])
The program creates a list of dictionaries, writes it to JSON (note that a JSON file can have an array as its root element, not just an object), loads it back, and filters for incomplete tasks. The output would be 'Study for quiz' and 'Finish essay'. This demonstrates a practical use case for JSON—persisting application state so data survives between program runs.Question 5: CRITICAL THINKING
import json
data = {"name": "Sam", "scores": (95, 88, 72), "joined": None}
with open('output.json', 'w') as f:
json.dump(data, f)
with open('output.json') as f:
result = json.load(f)
print(type(result['scores'])) # What type is this now?Show answer
(95, 88, 72) will actually serialize without error — Python's json module converts tuples to JSON arrays automatically. However, when you load the data back, it becomes a list [95, 88, 72], not a tuple. This is because JSON has no tuple type — it only has arrays, which Python maps to lists. So type(result['scores']) prints <class 'list'>. This is a subtle data loss issue: the round-trip changes the type. Second, None converts to JSON null and back to Python None correctly — no issue there. The lesson: always be aware that JSON supports fewer types than Python, so round-tripping may change data types silently. If preserving tuples is important, you would need to add custom serialization logic.SUMMARY
Lesson Summary
Summary
JSON (JavaScript Object Notation) is a lightweight, text-based format for storing and exchanging structured data. A JSON file is built from two container types—objects (curly braces) and arrays (square brackets)—plus primitive values: strings, numbers, booleans, and null. In Python, objects map to dicts, arrays map to lists, and the remaining types map naturally to str, int/float, bool, and None.
Python's built-in json module provides four essential functions: json.dump() writes to a file, json.dumps() returns a string, json.load() reads from a file, and json.loads() parses a string. The process of converting Python objects to JSON is called serialization, and the reverse is deserialization. Remember that JSON requires double quotes, forbids trailing commas and comments, and does not support Python-specific types like tuples or sets. Mastering JSON I/O prepares you for working with web APIs, configuration files, and data-driven applications.