DotDict
DotDict amplía el dict de Python con consulta, asignación y eliminación mediante atributos. Úsalo para registros dinámicos pequeños cuando sigas necesitando las operaciones de diccionario. Conserva los valores recibidos; no valida datos ni convierte tipos escalares.
Importación y uso directo
Sección titulada «Importación y uso directo»from orionis.support.types import DotDict
settings = DotDict({"server": {"port": 8000}})assert settings.server.port == 8000settings.server.port = 9000assert settings["server"]["port"] == 9000Inyección de dependencias
Sección titulada «Inyección de dependencias»La clase no depende de servicios del framework. Basta con construirla directamente. Orionis también puede inyectar un DotDict vacío en el constructor de otra clase; llénalo explícitamente para la operación que lo necesite. La construcción automática no carga datos de peticiones ni configuraciones de la aplicación.
import asynciofrom orionis.container.container import Containerfrom orionis.support.types import DotDict
class Report: def __init__(self, values: DotDict) -> None: self.values = values
async def main() -> None: class LocalContainer(Container): pass
report = await LocalContainer().make(Report) report.values.name = "Orionis" assert report.values["name"] == "Orionis"
asyncio.run(main())Construcción: constructor heredado de dict
Sección titulada «Construcción: constructor heredado de dict»DotDict(), DotDict(mapping, /, **kwargs) y DotDict(iterable, /, **kwargs) crean un diccionario mutable. Los argumentos de palabra clave sobrescriben las claves repetidas del origen. La construcción no envuelve anticipadamente los diccionarios anidados ni los que están dentro de listas. Las entradas inválidas siguen a dict: por ejemplo, pares de clave/valor mal formados producen ValueError y claves no hashables producen TypeError.
from orionis.support.types import DotDict
data = DotDict([("name", "old")], name="Orionis", config={"debug": True})assert data["name"] == "Orionis"assert type(data["config"]) is dictassert DotDict() == {}__getattr__(self, key: str) -> object | None
Sección titulada «__getattr__(self, key: str) -> object | None»El acceso por atributo utiliza este método cuando la búsqueda normal de Python no encuentra el nombre. Devuelve None si falta la clave. Un valor de tipo exacto dict se convierte en DotDict y el reemplazo se guarda en el padre. Los demás valores, incluidas las subclases de diccionario y los diccionarios dentro de listas, permanecen sin cambios. Los métodos existentes, como items, tienen prioridad sobre las claves; accede a esas claves con corchetes. Como los atributos ausentes devuelven None, hasattr(data, "missing") es True; comprueba la pertenencia de la clave.
from orionis.support.types import DotDict
data = DotDict(config={"debug": True}, items="stored value")assert data.config.debug is Trueassert data["config"] is data.configassert data.missing is Noneassert hasattr(data, "missing") is Trueassert "missing" not in dataassert callable(data.items)assert data["items"] == "stored value"__setattr__(self, key: str, value: object) -> None
Sección titulada «__setattr__(self, key: str, value: object) -> None»data.name = value guarda una entrada del diccionario y el método devuelve None. Un dict exacto se envuelve una vez; los niveles internos se envuelven cuando se accede a ellos por atributo. La operación reemplaza una entrada existente. No crea un atributo de instancia independiente.
from orionis.support.types import DotDict
data = DotDict()data.config = {"nested": {"enabled": True}}assert type(data["config"]) is DotDictassert type(data["config"]["nested"]) is dictdata.name = "Orionis"data.name = "Updated"assert data["name"] == "Updated"__delattr__(self, key: str) -> None
Sección titulada «__delattr__(self, key: str) -> None»del data.name elimina la entrada correspondiente. El método devuelve None y produce AttributeError si la clave no existe, encadenando el KeyError original.
from orionis.support.types import DotDict
data = DotDict(name="Orionis")del data.nameassert "name" not in datatry: del data.nameexcept AttributeError as error: assert isinstance(error.__cause__, KeyError)get(self, key: str, default: object | None = None) -> object | None
Sección titulada «get(self, key: str, default: object | None = None) -> object | None»Devuelve el valor almacenado o default (None por defecto). Si el resultado es un dict exacto, lo envuelve y lo guarda bajo key. Esto también se aplica a un diccionario usado como valor predeterminado: consultar una clave ausente con ese valor inserta el diccionario envuelto. Los demás valores predeterminados no insertan entradas. No hay conversión de los valores.
from orionis.support.types import DotDict
data = DotDict(config={"debug": True})assert data.get("config").debug is Trueassert data.get("absent") is Noneassert "absent" not in datafallback = data.get("created", {"port": 8000})assert isinstance(fallback, DotDict)assert data["created"] is fallbackassert fallback.port == 8000export(self) -> dict[str, Any]
Sección titulada «export(self) -> dict[str, Any]»Devuelve un nuevo diccionario estándar y convierte recursivamente los valores que son diccionarios. No modifica el origen. Solo recorre valores de diccionario: listas, tuplas, objetos personalizados y su contenido conservan sus referencias. Las subclases de diccionario se normalizan. No hay caché de ciclos; un ciclo alcanzado a través de valores de diccionario produce RecursionError.
from orionis.support.types import DotDict
rows = [DotDict(id=1)]data = DotDict(config=DotDict(debug=True), rows=rows)result = data.export()assert type(result) is dictassert type(result["config"]) is dictassert result["rows"] is rowsassert type(result["rows"][0]) is DotDictresult["config"]["debug"] = Falseassert data.config.debug is Truecopy(self) -> DotDict
Sección titulada «copy(self) -> DotDict»Devuelve un nuevo DotDict y copia recursivamente los valores de diccionario a nuevos objetos DotDict. Aunque el docstring lo denomina “copia profunda”, este método comparte los valores que no son diccionarios, incluidas las listas mutables. No modifica el origen ni conserva la identidad compartida de los diccionarios. Los ciclos entre diccionarios producen RecursionError. Usa copy.deepcopy de Python cuando también debas copiar listas y otros valores compatibles.
from orionis.support.types import DotDict
data = DotDict(config={"debug": True}, rows=[1])result = data.copy()assert type(result) is DotDictassert type(result["config"]) is DotDictresult.config.debug = Falseassert data.config.debug is Trueresult.rows.append(2)assert data.rows == [1, 2]Heredado: clear(self) -> None
Sección titulada «Heredado: clear(self) -> None»Elimina todas las entradas y devuelve None.
from orionis.support.types import DotDict
data = DotDict(a=1)assert data.clear() is Noneassert data == {}Heredado: fromkeys(iterable, value=None, /)
Sección titulada «Heredado: fromkeys(iterable, value=None, /)»El método de clase heredado devuelve un nuevo DotDict y asigna la misma referencia de value a todas las claves. Su valor predeterminado es None; no envuelve diccionarios. Las claves no hashables producen TypeError.
from orionis.support.types import DotDict
shared = []data = DotDict.fromkeys(["first", "second"], shared)assert type(data) is DotDictdata["first"].append(1)assert data["second"] == [1]assert DotDict.fromkeys(["unset"])["unset"] is NoneHeredado: items(self)
Sección titulada «Heredado: items(self)»Devuelve una vista dinámica de pares (clave, valor) sin envolver valores anidados. No modifica el diccionario. Cambiar su tamaño durante la iteración puede producir RuntimeError.
from orionis.support.types import DotDict
data = DotDict(a=1)view = data.items()data["b"] = 2assert list(view) == [("a", 1), ("b", 2)]Heredado: keys(self)
Sección titulada «Heredado: keys(self)»Devuelve una vista dinámica de claves en orden de inserción, sin modificar el diccionario. Iterar mientras cambia su tamaño puede producir RuntimeError.
from orionis.support.types import DotDict
data = DotDict(a=1)view = data.keys()data["b"] = 2assert list(view) == ["a", "b"]Heredado: values(self)
Sección titulada «Heredado: values(self)»Devuelve una vista dinámica de los valores almacenados sin envolver diccionarios ni modificar el origen. Iterar mientras cambia su tamaño puede producir RuntimeError.
from orionis.support.types import DotDict
data = DotDict(config={"debug": True})view = data.values()assert type(next(iter(view))) is dictdata["count"] = 2assert len(view) == 2Heredado: pop(self, key, /, [default])
Sección titulada «Heredado: pop(self, key, /, [default])»Elimina y devuelve una entrada sin convertir su valor. Si la clave está ausente, devuelve el valor predeterminado indicado; si no se indicó ninguno, produce KeyError. No hay un valor predeterminado implícito de None.
from orionis.support.types import DotDict
data = DotDict(config={"debug": True})assert type(data.pop("config")) is dictassert data.pop("missing", None) is Nonetry: data.pop("missing")except KeyError: assert data == {}Heredado: popitem(self)
Sección titulada «Heredado: popitem(self)»Elimina y devuelve el par (clave, valor) insertado más recientemente. Produce KeyError si está vacío y no envuelve el valor devuelto.
from orionis.support.types import DotDict
data = DotDict(a=1, b=2)assert data.popitem() == ("b", 2)assert data == {"a": 1}Heredado: setdefault(self, key, default=None, /)
Sección titulada «Heredado: setdefault(self, key, default=None, /)»Devuelve un valor existente o inserta y devuelve default si la clave no existe. Ninguna ruta envuelve valores de diccionario. El valor predeterminado es None. Las claves no hashables producen TypeError.
from orionis.support.types import DotDict
data = DotDict()fallback = {"debug": True}assert data.setdefault("config", fallback) is fallbackassert type(data["config"]) is dictassert data.setdefault("config", {"debug": False}) is fallbackassert data.setdefault("unset") is NoneHeredado: update(self, [mapping_or_iterable], /, **kwargs) -> None
Sección titulada «Heredado: update(self, [mapping_or_iterable], /, **kwargs) -> None»Añade o reemplaza entradas y devuelve None. Los argumentos de palabra clave tienen prioridad sobre el origen posicional. No envuelve diccionarios. Las entradas inválidas pueden producir TypeError o ValueError; las entradas procesadas antes del error pueden quedar guardadas.
from orionis.support.types import DotDict
data = DotDict(a=1)assert data.update({"a": 2, "config": {"debug": True}}, a=3) is Noneassert data["a"] == 3assert type(data["config"]) is dictProtocolos de diccionario
Sección titulada «Protocolos de diccionario»Estas operaciones se heredan de dict y de sus protocolos de objeto, sin conversión específica de valores de DotDict. La tabla muestra sus puntos de entrada de Python. Los cambios de tamaño durante la iteración pueden producir RuntimeError; las operaciones por clave exigen claves hashables.
from orionis.support.types import DotDict
data = DotDict(a=1, b=2)data["config"] = {"debug": True}assert type(data["config"]) is dictassert data["a"] == 1del data["config"]assert list(data) == ["a", "b"]assert list(reversed(data)) == ["b", "a"]assert len(data) == 2 and bool(data)assert "a" in dataassert data == {"a": 1, "b": 2}assert data != {"a": 9}merged = data | {"b": 3}assert type(merged) is dict and merged["b"] == 3reverse_merged = {"b": 0} | dataassert type(reverse_merged) is dict and reverse_merged["b"] == 2original = datadata |= [("c", 3)]assert data is original and data.c == 3assert repr(data) == "{'a': 1, 'b': 2, 'c': 3}"assert str(data) == repr(data)try: data["missing"]except KeyError: pass__hash__ = None
Sección titulada «__hash__ = None»DotDict es mutable y no es hashable. Llamar a hash(data) o usar una instancia como clave de diccionario produce TypeError.
from orionis.support.types import DotDict
try: hash(DotDict(a=1))except TypeError: passCopia y serialización de Python
Sección titulada «Copia y serialización de Python»No se define __copy__, __deepcopy__ ni un hook de serialización personalizado. copy.copy de Python usa el protocolo de reducción heredado y crea un DotDict superficial; copy.deepcopy copia recursivamente el contenido compatible. Un recorrido de pickle conserva el tipo DotDict para valores serializables normales. JSON lo acepta como diccionario y su decodificación devuelve un dict estándar; se aplican las restricciones normales de JSON sobre claves, valores y ciclos. export() no codifica JSON.
import copyimport jsonimport picklefrom orionis.support.types import DotDict
data = DotDict(rows=[1])shallow = copy.copy(data)deep = copy.deepcopy(data)restored = pickle.loads(pickle.dumps(data))assert type(shallow) is DotDict and shallow["rows"] is data["rows"]assert type(deep) is DotDict and deep["rows"] is not data["rows"]assert type(restored) is DotDict and restored == dataassert json.loads(json.dumps(data)) == {"rows": [1]}