Enabling dot notation and IDE autocompletion
Installation • Features • Documentation • Competitors • Citation
MetaDict is designed to behave exactly like a dict
while enabling (nested) attribute-style key access/assignment with IDE autocompletion support.
Many libraries claim to do the same, but fail in different ways (see Competitors).
$ pip install metadict
- Attribute-style key access and assignment (dot notation) with IDE autocompletion support
from metadict import MetaDict cfg = MetaDict() cfg.optimizer = 'Adam' print(cfg.optimizer) >> Adam
- Nested key assignment similar to
defaultdict
fromcollections
cfg = MetaDict(nested_assignment=True) cfg.model.type = 'Transformer' print(cfg.model.type) >> Transformer # or restrict nested assignment via context manager cfg = MetaDict() with cfg.enabling_nested_assignment() as cfg: cfg.model.type = 'Transformer' cfg.new_model.type = 'MLP' >> AttributeError: 'MetaDict' object has no attribute 'new_model'
- Is a
dict
dict_config = {'model': 'Transformer', 'optimizer': 'Adam'} cfg = MetaDict(dict_config) print(isinstance(cfg, dict)) >> True print(cfg == dict_config) >> True
- Inbuilt
json
supportimport json cfg = MetaDict({'model': 'Transformer'}) print(json.loads(json.dumps(cfg))) >> {'model': 'Transformer'}
- Recursive conversion to
dict
cfg = MetaDict({'models': [{'name': 'Transformer'}, {'name': 'MLP'}]}) print(cfg.models[0].name) >> Transformer cfg_dict = cfg.to_dict() print(type(cfg_dict['models'][0])) >> <class 'dict'> # Note: Appending a `dict` to a list within a `MetaDict` does not convert the `dict`. # MetaDict does not overwrite `list` so intercepting `append`. `extend`, etc. is currently not possible. # Simply wrap the appended or extended `dict` as a `MetaDict`. cfg.models.append({'name': 'RNN'}) print(isinstance(cfg.models[-1], MetaDict)) >> False cfg.models.append(MetaDict({'name': 'RNN'})) print(isinstance(cfg.models[-1], MetaDict)) >> True
- No namespace conflicts with inbuilt methods like
items()
,update()
, etc.cfg = MetaDict() # Key 'items' is assigned as in a normal dict, but a UserWarning is raised cfg.items = [1, 2, 3] >> UserWarning: 'MetaDict' object uses 'items' internally. 'items' can only be accessed via `obj['items']`. print(cfg) >> {'items': [1, 2, 3]} print(cfg['items']) >> [1, 2, 3] # But the items method is not overwritten! print(cfg.items) >> <bound method Mapping.items of {'items': [1, 2, 3]}> print(list(cfg.items())) >> [('items', [1, 2, 3])]
- References are preserved
params = [1, 2, 3] cfg = MetaDict({'params': params}) print(cfg.params is params) >> True model_dict = {'params': params} cfg = MetaDict(model=model_dict) print(cfg.model.params is params) >> True # Note: dicts are recursively converted to MetaDicts, thus... print(cfg.model is model_dict) >> False print(cfg.model == model_dict) >> True
Check the Test Cases for a complete overview of all MetaDict features.
- Addict
- No key autocompletion in IDE
- Nested key assignment cannot be turned off
- Newly assigned
dict
objects are not converted to support attribute-style key access - Shadows inbuilt type
Dict
- Prodict
- No key autocompletion in IDE without defining a static schema (similar to
dataclass
) - No recursive conversion of
dict
objects when embedded inlist
or other inbuilt iterables
- No key autocompletion in IDE without defining a static schema (similar to
- AttrDict
- No key autocompletion in IDE
- Converts
list
objects totuple
behind the scenes
- Munch
- Inbuilt methods like
items()
,update()
, etc. can be overwritten withobj.items = [1, 2, 3]
- No recursive conversion of
dict
objects when embedded inlist
or other inbuilt iterables
- Inbuilt methods like
- EasyDict
- Only strings are valid keys, but
dict
accepts all hashable objects as keys - Inbuilt methods like
items()
,update()
, etc. can be overwritten withobj.items = [1, 2, 3]
- Inbuilt methods don't behave as expected:
obj.pop('unknown_key', None)
raises anAttributeError
- Only strings are valid keys, but
@article{metadict,
title = {MetaDict - Enabling dot notation and IDE autocompletion},
author = {Hillebrand, Lars},
year = {2022},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/LarsHill/metadict}},
}