Concepts / Loading JSON Data in Python

Loading JSON Data in Python

A dataset entry for instruction fine-tuning is a Python dictionary with 'instruction', 'input', and 'output' keys.

  • Programming
Interactive lab

Try it: Parsing JSON into Python

How json.loads() reads JSON text token by token and builds Python dicts, lists, strings, numbers, True/False and None, how an access path like data["users"][0]["name"] walks that structure, and what json.dumps() writes back.

How it works

  1. The scanner reads the next token: a brace or bracket, a string in double quotes, a number, true / false / null, or a ',' / ':' delimiter.
  2. '{' starts a Python dict and '[' a list; both are pushed on a parse stack until their closing '}' or ']'.
  3. Inside a dict every key must be a double-quoted string followed by ':' and a value; items are separated by ','.
  4. Anything else stops the parse with JSONDecodeError, reporting the message, line, column and character position.
  5. The access path is applied one subscript at a time: dicts take keys (KeyError if missing), lists take integer indexes (IndexError if out of range).
  6. json.dumps() turns the Python objects back into JSON text (True → true, None → null), optionally indented.

Default run (43 steps): json.loads() receives 105 characters of text. The scanner starts at char 0 and reads one token at a time. … json.dumps(data, indent=2) turns the Python objects back into JSON text (171 characters): True → true, None → null, and strings get double quotes.

Simplified: Written from scratch to match CPython 3.12's json module (messages and positions checked against it); input is limited to 400 characters and 24 nesting levels, and the access path accepts only ["key"] and [index] subscripts. Python 3.13 reports a trailing comma in an object with a different message.

Educational simulation

Loading the simulation…

Starting From a Printed Entry

Suppose a dataset has already been loaded from a JSON file into a Python variable called data, and you print one of its entries. What the print statement shows is the most direct evidence of how the entry is built. Before defining anything about instruction fine-tuning, it helps to look at the data itself. The first step in this article is to predict what kind of Python object an entry with several labeled parts most likely is.

What do you think happens?

An entry in the dataset has several labeled parts, such as an instruction, an input, and an output. What kind of Python object is it most likely to be?

  • A list of three strings

  • A dictionary with three keys

  • A tuple with three positions

  • A single string with line breaks

Reveal answer
Answer:

A dictionary with three keys

Each entry is a dictionary with 'instruction', 'input', and 'output' keys. Because the parts are labeled, they are read by key rather than by position.

The reason for the prediction is that the dataset is stored as one Python object in memory. The source downloads an instruction dataset in JSON format, loads it into Python, and prints how many entries it contains. The file is about 204 KB, which is small enough for the whole file to be held in memory as a single object. Every idea in the rest of this article explains some part of how the single printed number is produced, and how the individual entries are shaped.

What a Training Entry Contains

Definition

A dataset entry for instruction fine-tuning is a Python dictionary with 'instruction', 'input', and 'output' keys.

The three keys have distinct roles even though they all sit in one object. The instruction tells the model what to do. The input holds the material the task works on. The output holds the answer the model should learn to produce. In the first printed entry of the source, the task is a spelling task: the instruction describes the task, the input holds the word to work on, and the output holds the correct answer.

entryPython dictionary'instruction'what the model should do'input'material the task works on,may be empty'output'answer the model shouldlearnkeykeykey
Which key holds which part of a training example, and how does each key map to its value?

The input field is not always filled in. In the second entry the source examines, the same three keys appear, but the input has no content at all, so the instruction stands on its own. The input field may occasionally be empty, so code that reads entries should handle that case. An empty input does not mean the entry is broken; it means the task can be described completely by the instruction alone.

python
Notes on the code
  • The whole entry is one dictionary with three string keys
  • entry['instruction'] reads the field by its key name
  • Comparing the input to an empty string lets code detect the empty-input case

Reading Fields by Key

Because each entry is a dictionary, you read its parts by key rather than by position. If you want the instruction of an entry, you ask for entry['instruction'], and the key name is what identifies the field. Keys are case-sensitive strings in Python, so the names have to match the template exactly to retrieve the right value. Writing entry['Instruction'] with a capital letter would not find the same field.

Before
print(entry['Instruction'])

The key 'Instruction' has a capital I, which does not match the stored key.

After
print(entry['instruction'])

The key 'instruction' matches the stored key exactly, so the value is returned.

Where Entries Fit in Instruction Fine-Tuning

Instruction fine-tuning means training a model on a dataset in which the input-output pairs are explicitly provided. The entries you have just examined are those pairs: each one supplies an instruction and an input, along with the output the model should produce for them. The entries are the working units of the training data.

Entries can be arranged for an LLM in different ways. These arrangements are called prompt styles. The source names two examples used in training notable LLMs, the Alpaca style and the Phi-3 style. Prompt styles are different formats for arranging entries for LLM training, and they are separate from the dictionary structure of an entry. The same dictionary can be turned into different prompt text, but the three keys that store the entry stay the same.

From JSON Text to Python Values

Definition

JSON is a human readable, machine friendly data interchange format whose structure mirrors Python dictionaries.

The format is built to match Python dictionaries. A JSON object is written with curly braces and key-value pairs, and a JSON list is written with square brackets. When Python reads a JSON object, it produces a dictionary, and a JSON list becomes a Python list. This resemblance is why JSON loads into Python so directly.

JSON text in the filePython value after loadingWhat stays the same
Object with curly braces and key-value pairsdictKeys and values are kept
List with square bracketslistElements keep their order
String in quotesstrThe text is unchanged
Numberint or floatThe numeric value is kept

How JSON structure maps onto Python values

python
Notes on the code
  • json_text is a string containing a single JSON object with two or more keys
  • json.loads() parses the string into a Python value
  • The result is a dictionary, so its fields are read by key

Tracing the Load Function

A common pattern is a function that first checks whether the file is already on disk, downloads it only when it is missing, and then loads it. The order of these steps matters. Before fetching anything, the function asks whether the file already exists. The os.path.exists() function takes a file path and returns True when a file is present at that path and False otherwise. The check is written with a leading not, so the download branch runs only when the file is missing.

File exists?os.path.exists()Download fileurlopen, decode, writejson.load()open file in read modeParsed Python datalist of entriesRead local textfile already presentmissingpresentthenthenreturns
In what order do the existence check, the download, and json.load() run, and which branch is skipped when the file already exists?

The function has two branches that both end in the same place. When the file is missing, the program opens a connection to the URL with urllib.request.urlopen(), reads the response, decodes it from bytes into text, and writes the text to the local file. When the file is present, the program skips the download and reads the local text directly. In both cases the next step opens the file again and passes it to json.load(), which returns the parsed data. When the file already exists, the download step is skipped entirely.

python
Notes on the code
  • The leading not means the download runs only when the file is missing
  • urlopen fetches the file, and decode turns the bytes into text
  • The second with block reopens the file and passes the file object to json.load()

The loading step is a with block that opens the file in read mode and passes the file object to json.load(). The with block closes the file automatically when the block ends, even if an error interrupts it. Note that json.load() takes a file object, not a file path and not a string.

Mistakes When Loading JSON

  • Common mistake

    Using json.loads() on a file object

    What it looks like
    data = json.loads(f)
    Why it fails

    json.loads() takes a string already in memory. The name ends in s because it works on text, while json.load() takes an open file object.

    Do this instead

    Use data = json.load(f) when f is an open file object.

  • Common mistake

    Passing a file path to json.load()

    What it looks like
    data = json.load('dataset.json')
    Why it fails

    json.load() takes a file object, not a file path and not a string.

    Do this instead

    Open the file in a with block first, then pass the open file object to json.load().

  • Common mistake

    Assuming the input field always has text

    What it looks like
    print(entry['input'].upper())
    Why it fails

    The input field may occasionally be empty, and empty input is a valid case in the dataset.

    Do this instead

    Check whether entry['input'] is empty before using it, and handle the empty case.

  • Common mistake

    Mismatching key names

    What it looks like
    entry['Output']
    Why it fails

    Keys are case-sensitive strings, so the lookup fails when the name does not match the stored key.

    Do this instead

    Use the exact key name 'output'.

  • Common mistake

    Counting from one when indexing a list, which skips the first element

  • Common mistake

    Forgetting that the printed number is the length of the list, not the index of the last entry

Tracing a Value Through the Program

Once the data is loaded, the program can index into the list. The top-level structure is a list of 1,100 entries, so index 50 refers to the fifty-first entry, since Python indexing starts at zero. Each element is a dictionary, because JSON objects become dictionaries when loaded. The source prints one entry with a labeled line, so you can see the shape of a single record before writing code that processes all of them. Printing one record first is a useful habit whenever you load a dataset you have not inspected before.

JSON fileabout 204 KB on diskjson.load()parses the filedatalist of 1,100 entriesdata[50]fifty-first entryPrinted entrydictionary with three keysreadreturnsindex 50print
As the value moves from the file through json.load() to the variable and into the printed output, at which step does it first differ from what is expected?
Worked example

Finding where an unexpected entry comes from

A learner expects data[50] to be the fiftieth entry, but the printed entry is one position later than they expected. Trace the value through the loading code to find the step where the expectation goes wrong.

  1. 1
    Check the source

    The file is a single JSON list, so json.load() returns a Python list of 1,100 entries.

  2. 2
    Check the index

    Python indexing starts at zero, so data[50] is the fifty-first element, not the fiftieth.

  3. 3
    Check the element type

    Each element is a dictionary, because each JSON object in the list becomes a dictionary after loading.

  4. 4
    Locate the mismatch

    The value first differs from the expectation at the indexing step, not at json.load(). The file and the parsed list are correct; the count assumption is wrong.

Result

The unexpected position comes from counting from one. The fix is to remember that index 50 is the fifty-first entry, and the loading step did not introduce the error.

Practice Locating the Faulty Step

MEDIUM

A loading function checks whether 'data.json' exists, downloads it when it is missing, and then calls json.load() on the file. A learner reports that the program prints a dictionary when they expected a list. Trace the values through the function and identify which step is responsible for the unexpected result, then state what the function should print instead.

Hints
  • Start at the file on disk and follow the value through each step in order
  • Ask what type json.load() returns when the top-level JSON structure is a list
  • Consider whether the code indexes the list or prints the whole object
EASY

Write a short line of code that reads the input field of the first entry in a loaded list named data, and use an if statement to print a message when the input is empty.

Hints
  • Use data[0] to reach the first entry, then use a string key
  • Compare the input value to an empty string

Key Takeaways

  • A dataset entry for instruction fine-tuning is a Python dictionary with 'instruction', 'input', and 'output' keys, read by key name, and the input may be empty.
  • JSON mirrors Python: objects become dictionaries and lists become Python lists, and json.load() takes an open file object while json.loads() takes a string.
  • A load function checks for the file with os.path.exists(), downloads only when it is missing, and then passes the file to json.load() in both branches.
  • When tracing a loading program, follow the value step by step, since an unexpected result often appears at indexing or counting rather than at the load itself.
  • Prompt styles such as Alpaca and Phi-3 are different ways to format the same entries and are separate from the dictionary structure.

Related concepts

More concepts starting with L