runtime
82 / 250
lesson 82 Nested Data Structures · intermediate

Missing keys: get and safe defaults

APIs leave keys out when there is nothing to say. `get` reads a key that may be missing and gives back a default instead of stopping the program.

You'll be able to
  • Use record.get(key) and record.get(key, default) and say what each returns for a missing key
  • Explain why a key that holds None does not use the default
  • Chain get with a {} default to reach safely into a dictionary that may be missing
The idea

In the USGS feed, an earthquake nobody reported feeling has "felt": null (None in Python), and some sources leave keys such as tsunami out entirely. Customer records are the same: a phone number that was never entered isn't stored as an empty value, the key just isn't there.

Brackets demand the key: props["tsunami"] stops the program with KeyError when it is missing. The dictionary method `get` asks instead: props.get("tsunami") returns None when the key is missing, and props.get("tsunami", 0) returns the default you chose.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · get on a USGS properties record
props = {"mag": 4.6, "place": "44 km WSW of Cabangahan, Philippines", "felt": 1, "alert": None}
print(props.get("felt"))
print(props.get("tsunami"))
print(props.get("tsunami", 0))
print(props.get("alert", "none issued"))
example-2.py · Brackets on a missing key
props = {"mag": 4.6, "felt": 1}
print(props["felt"])
print(props["tsunami"])

When a whole inner dictionary can be missing, give get an empty dictionary as the default. feature.get("properties", {}) always returns a dictionary, so the next get is safe either way. When None and "missing" should mean the same thing, test the result with is None and choose the value yourself.

example-3.py · Felt reports, whatever the record looks like
def felt_reports(feature):
    props = feature.get("properties", {})
    felt = props.get("felt")
    if felt is None:
        return 0
    return felt

features = [
    {"id": "us6000pw8f", "properties": {"mag": 4.6, "felt": 1}},
    {"id": "us6000pw77", "properties": {"mag": 4.7, "felt": None}},
    {"id": "nc75123456"},
]
for f in features:
    print(f["id"], felt_reports(f))

When to use it: for keys the data is allowed to leave out: optional profile fields, flags that only appear when set, nested sections that some records don't have. Mistakes to avoid: expecting the default when the key holds None; using get for a key that must exist, which hides a broken record behind a None that fails somewhere later; and writing props.get["felt"] with brackets instead of parentheses (get is a method you call).

Review
  • d.get(k) returns None for a missing key; d.get(k, default) returns your default.
  • A key that holds None is not missing: get returns None, not the default.
  • d.get("inner", {}) lets you keep chaining when a whole section may be absent.
  • Next: records often hold lists, such as an order's line items. An inner loop walks them.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Missing keys: get and safe defaults — Nested Data Structures · Runtime