SimpleNamespace: Lightweight Attribute Objects

Published on: August 29, 2026
Reading time: 5 minutes
Close-up view of a computer screen displaying code in a software development environment.

Sometimes you need a simple object that groups values behind attribute access without defining a full class. types.SimpleNamespace provides exactly that: a mutable container backed by __dict__, constructed from keyword arguments, with a readable representation and equality based on stored attributes.

This guide explains how to create namespaces, convert dictionaries, add and remove attributes, compare instances, copy objects, handle nested data, integrate with JSON and argparse, and decide when a dataclass, TypedDict, NamedTuple, or regular class is more appropriate.

Your first SimpleNamespace

from types import SimpleNamespace

user = SimpleNamespace(name="Ana", active=True)
print(user.name)
print(user.active)

Keyword arguments are inserted into the instance __dict__. There is no field declaration, runtime validation, or automatic conversion.

Adding attributes later

user.id = 42
user.email = "ana@example.com"

The object is dynamic and mutable. This is convenient for prototypes and temporary state, but a misspelled name may silently create a new attribute.

Building from a dictionary

data = {"host": "localhost", "port": 8000}
config = SimpleNamespace(**data)
print(config.port)

Keys must be strings accepted as keyword names. Keys containing hyphens, spaces, or non-string values cannot be expanded directly with **.

Converting back to a dictionary

mapping = vars(config)

vars(config) returns the actual attribute dictionary, not a copy. Mutating it changes the namespace.

snapshot = vars(config).copy()

Create a copy when independent state is required.

Readable representation

print(SimpleNamespace(x=1, y=2))
# namespace(x=1, y=2)

The representation is helpful in tests and debugging, but it may display sensitive values. Redact passwords, tokens, and personal data before logging.

Equality

a = SimpleNamespace(x=1, y=2)
b = SimpleNamespace(y=2, x=1)
print(a == b)  # True

Equality compares attribute dictionaries. Insertion order does not matter. The class is mutable and not intended as a hashable dictionary key or set member.

Removing attributes

del user.email

Accessing the deleted attribute raises AttributeError. Use hasattr() or getattr(object, name, default) for optional data.

Dynamic getattr and setattr

field_name = "timeout"
setattr(config, field_name, 30)
value = getattr(config, field_name)

These functions are useful when names come from metadata. Validate an allowlist before accepting external field names, especially when callers could overwrite attributes with special meaning.

Nested namespaces

app = SimpleNamespace(
    database=SimpleNamespace(host="db", port=5432),
    debug=False,
)

Nested dictionaries are not converted automatically. Build nested namespaces explicitly when dot access is desirable.

Recursive conversion

def to_namespace(value):
    if isinstance(value, dict):
        return SimpleNamespace(
            **{key: to_namespace(item) for key, item in value.items()}
        )
    if isinstance(value, list):
        return [to_namespace(item) for item in value]
    return value

Before applying this helper to external data, verify that every key is a suitable identifier and that no unexpected special names are accepted.

JSON serialization

The default JSON encoder does not serialize SimpleNamespace directly. A small object can be converted with:

import json

text = json.dumps(config, default=vars)

default=vars may also expose attributes of other objects with __dict__. Explicit conversion is safer for public APIs.

Shallow and deep copies

from copy import copy

clone = copy(app)

A shallow copy creates another namespace while nested mutable values remain shared. Use deepcopy() only when the graph supports it and the extra cost is justified.

Using it with argparse

ArgumentParser.parse_args() returns a namespace-like object and can populate an existing instance:

from argparse import ArgumentParser
from types import SimpleNamespace

parser = ArgumentParser()
parser.add_argument("--port", type=int, default=8000)
config = parser.parse_args(namespace=SimpleNamespace())

For larger applications, validate and convert the parsed result to an explicit model before startup.

Prototyping and test fixtures

SimpleNamespace is effective for quick tests, stubs, fixtures, and internal return values when a formal class would add unnecessary ceremony. Attribute access can make result.value clearer than tuple indexes.

It is not a schema

The object does not declare required fields, types, defaults, or documentation. Static analyzers have little information about dynamic attributes. A dataclass or TypedDict gives a stronger long-lived contract.

SimpleNamespace versus dataclass

from dataclasses import dataclass

@dataclass
class Config:
    host: str
    port: int = 8000

Dataclasses provide explicit fields, type hints, predictable construction, immutability options, and better IDE support. Use SimpleNamespace when the shape is temporary or genuinely dynamic.

Versus TypedDict

TypedDict describes dictionaries accessed by keys and primarily supports static analysis. SimpleNamespace provides runtime attribute access. Match the abstraction to the real data format rather than converting only for stylistic preference.

Versus NamedTuple

NamedTuple is immutable, indexable, hashable, and has fixed fields. SimpleNamespace is mutable, not index-oriented, and accepts new attributes. NamedTuple is often better for stable lightweight records.

Versus a regular class

A normal class supports invariants, properties, methods, validation, and encapsulation. Once a temporary object gains behavior or becomes part of a public API, migrate it to an explicit class.

Providing defaults

SimpleNamespace has no field declaration for defaults. Use a factory:

def new_config(**overrides):
    values = {"host": "localhost", "port": 8000, "debug": False}
    unknown = set(overrides) - set(values)
    if unknown:
        raise TypeError(f"unknown options: {sorted(unknown)}")
    values.update(overrides)
    return SimpleNamespace(**values)

Checking unknown names prevents silent typos.

Calculated fields

You can store a calculated value, but it does not update automatically when dependencies change. Use a class property when a value should always be derived from current state.

Subclassing

SimpleNamespace can be subclassed, but once methods, validation, and fixed structure are needed, a regular class or dataclass usually communicates intent more clearly.

Security with external data

Do not convert arbitrary JSON to attributes and then use those attributes to control imports, filesystem paths, queries, or function calls without validation. Dot notation does not make input trusted.

Thread safety

The namespace provides no synchronization. Multiple threads mutating attributes require the same locking discipline as a shared dictionary. Prefer immutable snapshots for configuration read by many workers.

Common mistakes

  • Treating it as a validated model: any attribute can be created.
  • Using vars as an independent mapping: it returns the live dictionary.
  • Expecting recursive conversion: nested dictionaries remain dictionaries.
  • Publishing it as a stable API contract: fields are not declared.
  • Logging secrets: the repr includes attributes.
  • Assuming a shallow copy is isolated: nested objects remain shared.

Complete processing-result example

from types import SimpleNamespace

def process(lines):
    errors = []
    valid = []
    for number, line in enumerate(lines, 1):
        try:
            valid.append(normalize(line))
        except ValueError as error:
            errors.append((number, str(error)))

    return SimpleNamespace(
        total=len(lines),
        valid=valid,
        errors=errors,
        success=not errors,
    )

result = process(lines)
if result.success:
    save(result.valid)

The namespace works well as a simple internal result. If the result becomes part of a library’s public interface, a typed dataclass offers a clearer contract.

Conclusion

types.SimpleNamespace is a lightweight container for values accessed through attributes. It reduces boilerplate in prototypes, tests, and temporary structures while providing useful representation and equality behavior.

The official Python SimpleNamespace documentation defines the class. Use it for simple dynamic data and move to a dataclass, TypedDict, NamedTuple, or regular class when schema, validation, or behavior becomes important.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python ChainMap: Layered Mappings

    Learn Python ChainMap for layered configuration and scopes, including precedence, first-map writes, snapshots, and safe mutation.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    Detailed close-up of yellow and white albino python scales, capturing texture and pattern.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.pairwise: Analyze Consecutive Pairs

    Learn Python itertools.pairwise to analyze consecutive pairs, calculate deltas, detect transitions, gaps, and ordering problems.

    Ler mais

    Tempo de leitura: 4 minutos
    29/08/2026
    A detailed image of a reticulated python showcasing its patterned scales and intricate skin texture.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.batched: Process Iterables in Batches

    Learn Python itertools.batched to process iterables in chunks, control memory, use strict mode, and build resilient data pipelines.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    cmp_to_key: Use Legacy Comparators with sorted

    Learn Python cmp_to_key to adapt legacy comparators, sort with locale rules, preserve stability, and avoid inconsistent ordering.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    A person reads 'Python for Unix and Linux System Administration' indoors.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    total_ordering: Generate Consistent Comparisons

    Learn Python total_ordering to generate consistent comparisons, return NotImplemented, integrate dataclasses, and test ordering rules.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    inspect.signature: Inspect Function Parameters

    Learn Python inspect.signature to read parameters, bind arguments, preserve decorators, and build dynamic callable interfaces safely.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026