‘Namespaces are one honking great idea!’
Namespaces are powerful as they allow functions with the same names to exist in the same script, while also providing relatively-straightforward attribute access (pathlib.Path) and static analysis assistance. Futher, there are many times in which having access to namespace rather than, e.g., a dict could be wildly useful. Introducing: SimpleNamespace.
Lurking in the types package in the standard library is the SimpleNamespace object. A simple, straightforward wrapper allowing arbitrary namespace attribute access without needing to construct a class. One of the easiest ways to get started is by transforming a dict into a SimpleNamespace and comparing the differences.
from types import SimpleNamespace
data = {'name': 'Bjørn', 'age': 23}
# so something with 'name' requires:
print(data['name'])
# update age
data['age'] += 1
print(data['age']) # 24
ns = SimpleNamespace(**data)
print(ns.name)
ns.age += 1
print(ns.age) # 25The SimpleNamespace thereby allows the efficient creation of ad hoc objects. Unlike with namedtuple, these objects are flexible and mutable.
Another useful application is when reading in certain json objects. Suppose we have a complex json object we’re reading in. We can compare different ways of accessing:
import json
data = {'version': 1, 'characters': [{'name': 'Bjørn', 'age': 23}, {'name': 'Mari', 'age': 25}]}
json_str = json.dumps(data)
d = json.loads(json_str, object_hook=lambda d: SimpleNamespace(**d))
for ch in data['characters']:
print(ch['name'], ch['age'])
for ch in d.characters:
print(ch.name, ch.age) # particularly useful in a format stringExcept for small examples or ad hoc use cases, however, it’s probably a better idea to start implementing classes, especially with dataclasses. These are going to be more robust, provide IDE autocomplete, and are quite painless given the ease of making dataclasses.
Consider the above example when we can use a dataclass instead to read this structure:
from dataclasses import dataclass
from typing import List
@dataclass
class Character:
name: str
age: int
@dataclass
class Epic:
version: int
characters: List[Character]
epic = Epic(
version=data['version'],
characters=[Character(**c) for c in data['characters']],
)Here, we are still using a Namespace but a less simple one which provides better support and long-term maintainability. This structure, however, requires that a well-defined format exists. Prior to that, or when reading ad hoc structures, SimpleNamespaces can be a simple way to get access and explore the structure quickly, and without the repetitive punctuation required for dict objects.