Card 05/ 08
Open/Closed in the Wild: Extending Python's json Module
json.dumps cannot encode a date, and you teach it without editing a line of json.
Python's json module is closed in the strongest sense: it ships with Python, and you cannot edit it. This example shows how it was designed to be open anyway. It shares one thing with the discount rules: the closed code calls something it does not know in advance, which you supply.
Out of the box, json.dumps turns dictionaries, lists, strings and numbers into JSON text. It does not know what to do with a date.
import json
from datetime import date
order = {"id": 1042, "placed": date(2026, 11, 27)}
try:
print(json.dumps(order))
except TypeError as error:
print(f"TypeError: {error}")TypeError: Object of type date is not JSON serializableThe module gives you an extension point: the default argument. When dumps meets a value it cannot encode, it calls the function you passed, and encodes whatever that function returns.
import json
from datetime import date
def encode_extra(value):
if isinstance(value, date):
return value.isoformat()
raise TypeError(f"cannot encode {type(value).__name__}")
order = {"id": 1042, "placed": date(2026, 11, 27)}
print(json.dumps(order, default=encode_extra)){"id": 1042, "placed": "2026-11-27"}The date now comes out as an ISO 8601 string, and the json module did not change. Your function raises TypeError for anything else it does not recognise, which matches what json itself does, so callers see the same error as before for unsupported types.
The module offers a second extension point too: subclass json.JSONEncoder, override its default method, and pass the class as cls=. That is Meyer's original form of the principle, extension by inheritance, sitting next to Martin's form, extension by a supplied object. Both leave the library closed.
← → move through sections and cards