Mental model
A parser turns text into a Python object. Once you have a Python object (usually a dict or list), you work with it like any other Python data.
JSON text ───json.loads()───▶ Python dict/list
YAML text ───yaml.safe_load()───▶ Python dict/list
The parsed object is NOT magic. It is a normal dict with str keys. You index it (data["interface"]), loop over it (for k, v in data.items():), modify it, convert back.
Cisco objective 1.2 says “Describe parsing of common data format to Python data structures”. This topic is the deep answer; the data formats topic is the comparison; the parsing lab is the practice.
JSON: the two functions you need
import json
# From text to Python
raw = '{"interface": "GigabitEthernet0/0", "ip": "10.0.0.1"}'
data = json.loads(raw)
print(data["interface"]) # GigabitEthernet0/0
# From Python back to text
pretty = json.dumps(data, indent=2)
print(pretty)
| Function | Input | Output |
|---|---|---|
json.loads(s) | JSON string | Python dict/list |
json.load(f) | file object (opened in text mode) | Python dict/list |
json.dumps(obj, indent=2) | Python dict/list | JSON string |
json.dump(obj, f, indent=2) | obj + file object | nothing (writes to file) |
The s suffix means “string”; no s means “file”. That is the only naming trick.
How JSON maps to Python
| JSON | Python |
|---|---|
object {"k": "v"} | dict {"k": "v"} |
array [1, 2] | list [1, 2] |
string "hello" | str "hello" |
number (int) 42 | int 42 |
number (float) 3.14 | float 3.14 |
true / false | True / False |
null | None |
YAML: install first
PyYAML is not in Python’s standard library. Install once:
pip install PyYAML
Then:
import yaml
raw = """
interface: GigabitEthernet0/0
ip: 10.0.0.1
vlans:
- 10
- 20
"""
data = yaml.safe_load(raw)
print(data["ip"]) # 10.0.0.1
print(data["vlans"][0]) # 10
# Back to YAML text
print(yaml.dump(data, default_flow_style=False))
Always use safe_load, never load. Plain load can execute arbitrary Python code embedded in YAML tags, which is a remote code execution bug waiting to happen if you parse any YAML you did not write.
How YAML maps to Python
Same as JSON above, plus:
| YAML | Python |
|---|---|
| nested indented block | dict / list by indentation |
~ | None |
yes / no (YAML 1.1) | True / False |
| ` | ` (literal block) |
> (folded block) | multi-line str with newlines → spaces |
Reading from a file
JSON file:
with open("config.json") as f:
data = json.load(f)
YAML file:
with open("playbook.yml") as f:
data = yaml.safe_load(f)
with open(...) is the idiomatic Python way: the file closes automatically when the block ends, even if an exception is raised.
Writing to a file
JSON:
with open("backup.json", "w") as f:
json.dump(data, f, indent=2)
YAML:
with open("backup.yml", "w") as f:
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
default_flow_style=False keeps YAML in the indented block style you expect; True collapses it into one line like JSON.
Catching parse errors
A JSON file with a trailing comma raises json.JSONDecodeError. A YAML file with a bad indent raises yaml.YAMLError. Catch and report usefully:
import json
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
print(f"JSON parse failed at line {e.lineno} col {e.colno}: {e.msg}")
import yaml
try:
data = yaml.safe_load(raw)
except yaml.YAMLError as e:
print(f"YAML parse failed: {e}")
Printing the line number and column is the difference between a 30-second fix and a 30-minute hunt.
Try it in the Python REPL
The data-formats lab walks you through json.loads, yaml.safe_load and pretty-printing. 11 scripted steps. Shared with the data-formats topic.
Open the lab →The #1 mistake
Using yaml.load() instead of yaml.safe_load(). The plain load function can instantiate arbitrary Python classes from YAML tags like !!python/object/apply:os.system. Parsing a hostile YAML file with plain load can run commands on your machine. Always safe_load.
Second: confusing json.loads (string) with json.load (file). Easy mix-up because they are one character apart. If you get TypeError: the JSON object must be str, bytes or bytearray, not TextIOWrapper, you used loads when you meant load (or vice versa).
FAQ
Why do REST APIs use JSON and not YAML? JSON is strict, fast to parse, and widely supported in every language. YAML is human-friendly which is unnecessary for machine-to-machine communication.
Can I parse YAML with the json library? No. YAML 1.2 is a superset of JSON, so a YAML parser can read JSON, but a JSON parser cannot read YAML.
What is json.dumps(data, sort_keys=True) for? Produces the same JSON output for the same data regardless of key insertion order. Useful for computing hashes, comparing configs, writing tests.
My JSON has "null" as a string. How do I get an actual None? Fix the source JSON to use the literal null (no quotes). If you cannot fix the source, post-process: if data["x"] == "null": data["x"] = None.
What about streaming / large files? For very large JSON files use ijson (install separately). For large YAML, split into multiple documents separated by ---. Beyond 200-901 scope.
