Python names, type mismatches and missing dictionary keys — DedSec Project
Python names, type mismatches and missing dictionary keys NameError What fails and when NameError means a referenced name is not defined in the scope being executed. It can result from a…
NameError
What fails and when
NameError means a referenced name is not defined in the scope being executed. It can result from a spelling error, a conditional assignment that never ran, using a name before initialization, or importing from a different module than expected. A locally assigned name used too early inside a function may instead produce UnboundLocalError.
Self-contained executable example
Save this as 004_NameError.py and run python3 004_NameError.py. The example checks both the error and a valid case.
def discount(price, eligible):
amount = price
if eligible:
amount = price * 0.9
return amount
assert discount(100, True) == 90
assert discount(100, False) == 100
try:
eval("ammount", {})
except NameError as exc:
assert "ammount" in str(exc)
else:
raise AssertionError("misspelling was not caught")
Diagnostic sequence and safe repair
Start with the exact spelling in the traceback and the surrounding function scope; compare it to the assignment or import. Trace conditional branches with the failing input. Do not inject arbitrary values into globals() as a workaround; initialize explicitly or return a value from a function. In notebooks, rerun from a clean kernel to reveal hidden cell-order dependencies.
Practical lab and boundary test
Introduce a branch where amount is only assigned when eligible is true. Find the false-input failure, restore unconditional initialization, and write two tests. Then compare NameError with UnboundLocalError using a function that reads x before x = 1.
TypeError
What fails and when
A TypeError occurs when an operation or call receives objects it cannot use: adding str to int, calling a non-callable value, passing an unsupported keyword or omitting a required argument. Before converting types, decide whether the caller or the API contract is wrong. Automatic coercion can hide a broken data boundary.
Self-contained executable example
Save this as 006_TypeError.py and run python3 006_TypeError.py. The example checks both the error and a valid case.
def total_cost(price, quantity):
if not isinstance(price, (int, float)):
raise TypeError("price must be numeric")
if type(quantity) is not int:
raise TypeError("quantity must be an integer")
return price * quantity
assert total_cost(2.5, 3) == 7.5
try:
total_cost("2.5", 3)
except TypeError as exc:
assert "numeric" in str(exc)
else:
raise AssertionError("invalid type accepted")
Diagnostic sequence and safe repair
Inspect type(value), repr(value), the full function signature and the first failing frame you own. Distinguish text obtained from input() or JSON from numbers. Validate at the boundary; convert with explicit error handling only when the input format permits it. Note that bool is a subclass of int: use type(x) is int where True must not count as one unit.
Practical lab and boundary test
Extend the contract to reject negative quantities and non-finite prices. Should the failures be TypeError or ValueError? Document the distinction and assert the exact exception class, including a True quantity and a NaN price.
KeyError
What fails and when
Dictionary subscripting raises KeyError when the requested key is missing. Whether to catch it depends on the schema: an absent optional display name may have a safe default, whereas a missing transaction ID is a data-integrity fault. Blindly replacing every lookup with get() makes corrupted inputs look valid.
Self-contained executable example
Save this as 008_KeyError.py and run python3 008_KeyError.py. The example checks both the error and a valid case.
def label(record):
order_id = record["id"] # required
nickname = record.get("nickname")
return f"{order_id}: {nickname or 'Guest'}"
assert label({"id": 7}) == "7: Guest"
assert label({"id": 7, "nickname": "Ada"}) == "7: Ada"
try:
label({"nickname": "Ada"})
except KeyError as exc:
assert exc.args == ("id",)
else:
raise AssertionError("required key was optional")
Diagnostic sequence and safe repair
Print or log sorted(record.keys()) for non-sensitive test data, not complete production payloads. Compare the expected schema with actual parser output. Membership checks are appropriate when None is a valid stored value; dict.get cannot distinguish a missing key from an explicitly stored None without a sentinel.
Practical lab and boundary test
Create a sentinel = object() and tell apart absent nickname, nickname=None and nickname=''. Define a user-visible policy for each, while keeping id mandatory; test the three boundaries.