JSON to Python: Differences, Edge Cases & Pitfalls

Turn JSON into typed Python dataclasses with annotations, plus the Decimal and datetime parsing hooks they need.

The result is a typed dataclass, which static tools understand far better than raw dicts. Remember the standard json module will not build dataclasses for you (use pydantic or dacite), and neither Decimal nor datetime is serialisable without a custom default hook.

Format Differences

AspectJSONPython types
Type declarationsNone; runtime inferenceAnnotations optional; not enforced at runtime
NamingcamelCase / snake_casePEP 8 prefers snake_case; convert or alias
NullabilitynullOptional[T] is a hint only; still check at runtime
IntegersOne number typeint has arbitrary precision (big ints are safe here)
Floatsnumberfloat is a double; use Decimal for money
DatesStringsConvert to datetime manually and handle timezones
ImmutabilityNot applicablefrozen dataclass or NamedTuple
ValidationNonepydantic adds runtime validation and coercion

Edge Cases

  • Python ints never overflow, but the value still loses precision if a JS consumer parses it beyond 2^53 — safe here is not safe end to end.
  • 0.1 + 0.2 != 0.3 is inherent to binary floats; money needs Decimal and string transport.
  • Naive datetimes compared across timezones either raise or silently give wrong results — always use aware datetimes.
  • A mutable default (items: list = []) is shared across instances; use default_factory.

Common Pitfalls

  • Passing plain dicts everywhere hides misspelled fields until runtime and defeats static checking.
  • Money as float makes 0.1 + 0.2 leave a 5.55e-17 discrepancy in the books.
  • Mixing naive and aware datetimes produces intermittent TypeErrors in production.
  • A dataclass list field with a mutable default is shared by every instance, so data leaks between records.
  • JSON null maps to Python None, yet an Optional annotation only matters to static checkers — runtime code still needs a null check or it raises AttributeError.

Related Tools