CHAPTER 22 · INTERMEDIATE4 min read

JSON and CSV

Turn external representations into validated Python values and export data without breaking its structure.

Python 3.12+Free to readModule 5 of 13
YOUR NEXT SMALL WINS

By the end, you’ll be able to…

  • Choose JSON or CSV for a data exchange.
  • Read and write structured data with standard library tools.
  • Validate shape and convert values at an import boundary.

01Choose a representation for the shape

JSON represents nested objects, arrays, strings, numbers, booleans, and null. It suits a configuration containing settings and a list of tasks. CSV represents rows and columns and is convenient for spreadsheets or tabular exports. Neither format defines your application rules: valid JSON can still contain a negative quantity, and a valid CSV can omit a required column.

Keep serialization separate from business calculations. Decode the representation, validate its structure, convert values, and then pass clean data into the rest of your program. This boundary makes error messages precise and prevents every calculation from repeating defensive parsing.

json_roundtrip.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

02Serialization changes some Python types

JSON object keys are strings. Tuples become arrays and return as lists after decoding. Datetimes and custom class instances need an explicit representation, such as an ISO timestamp or a dictionary of fields. A round trip preserves the agreed data model, not every Python object identity or type.

Use dumps and loads for strings, and dump and load with file handles. Indentation helps humans review a saved file; it is not validation. Catch JSONDecodeError when reporting malformed input, then separately check expected keys and types. Avoid pickle for untrusted interchange because loading pickle can execute code.

validated_json.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

03Let the CSV module handle delimiters

A field can contain a comma, a quote, or even a newline. Splitting a line on commas cannot distinguish a separator from a comma inside a quoted field. csv.DictReader maps header names to values, while DictWriter writes columns in an explicit order and applies the quoting rules.

Open CSV files with newline="" so the csv module controls newline handling. CSV readers ordinarily return strings, even when a cell looks numeric. Convert the fields you need, report the row number on failure, and decide how blank values are represented. A missing numeric value should not quietly become zero unless that is the documented rule.

csv_roundtrip.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.

04Design an import contract

For an import, document required headers, accepted value ranges, treatment of unknown columns, and whether one bad row rejects the whole file. A small internal tool may stop at the first error. A batch import may collect row-specific errors and reject all writes until validation succeeds. Both are defensible if the behavior is explicit.

Preserve identifiers as strings when leading zeros matter. A postal code or product code is not a quantity just because it contains digits. Also remember that CSV quoting does not make spreadsheet formulas harmless when a human opens an export; apply a separate spreadsheet-safe policy when exporting untrusted cell content for spreadsheet use.

LET IT CLICK

The ideas worth keeping.

  • Decode first, then validate the application contract.
  • Use csv tools for quoting and newline handling.
  • Convert quantities explicitly while preserving textual identifiers.
TURN UNDERSTANDING INTO SOMETHING YOU CAN DO

Make it yours.

Type and test your code right here in the interactive workspace. Run your solution, check the output, and compare with the worked guide when ready.

01

Validate a task payload

Decode JSON containing a title. Require a nonempty string after trimming and return the trimmed title. Reject missing titles and non-object roots.

your_turn_1.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.pyPython
import jsondef task_title(text):    value = json.loads(text)    if not isinstance(value, dict):        raise ValueError("expected an object")    title = value.get("title")    if not isinstance(title, str) or not title.strip():        raise ValueError("title must be nonempty text")    return title.strip()assert task_title('{"title": "  Learn CSV  "}') == "Learn CSV"for text in ('[]', '{}', '{"title": " "}'):    try:        task_title(text)    except ValueError:        continue    raise AssertionError("invalid input was accepted")

JSON parsing establishes syntax only. The second phase enforces the application shape and normalizes the accepted title once.

02

Total an in-memory CSV

Use DictReader on CSV text to total quantity. Include an item containing a comma and keep its code 001 as text.

your_turn_2.py🐍Python
Ctrl + ↵
Output
Click Run or press Ctrl+Enter
Output will appear here after you run the code.
Explore a worked solution
one_possible_solution.pyPython
import csvimport iotext = 'code,item,quantity\n001,"Tea, green",3\n002,Coffee,2\n'rows = list(csv.DictReader(io.StringIO(text, newline="")))assert rows[0]["code"] == "001"assert rows[0]["item"] == "Tea, green"total = sum(int(row["quantity"]) for row in rows)assert total == 5print(total)

The reader understands quoted separators. Conversion is restricted to quantity, preserving identifier formatting.

A SMALL QUESTION. A USEFUL NEXT STEP.

What stayed with you?

Check the ideas while they’re fresh. Your answers stay in this page and feedback appears as you go.

A LITTLE ACTIVE RECALL0 / 3 answered
01json.loads succeeds on {"quantity": -3}. What has been established?
02Why use csv.reader instead of line.split(",")?
03Which field should usually remain a string?
⚡CODING CHALLENGE
🔒Required to Mark Lesson Complete

Validate a task payload

Decode JSON containing a title. Require a nonempty string after trimming and return the trimmed title. Reject missing titles and non-object roots.

EXPECTED OUTPUT
[Process exited with code 0 - No output]
challenge.pyPython 3
Ctrl + ↵
Execution Console
Click "Run & Verify" (or press Ctrl + Enter) to test your code against the challenge.

Keep exploring.

The official references behind this chapter, when you want a second angle or the full details.

One chapter closer.

Reading is a start. Trying it yourself makes the connection.

Solve the hands-on coding challenge in the knowledge section to verify your code and unlock chapter completion.