A Python object type that supports both dict and dot value getter

Revision history
Tags: python

Preface

Having a dict, I am unable to access its keys using dot notation

d = dict(a="one", b="two")
print(d.a)
# Traceback (most recent call last):
#   File "<stdin>", line 2, in <module>
# AttributeError: 'dict' object has no attribute 'a'

And to get strict dot notation, I could do something like this, using a class. But now I can’t access the values using the normal dict value getter:

class DictToDotNotation:
  def __init__(self, d):
    for k, v in d.items():
      setattr(self, k, v)

d = dict(a="one", b="two")
obj = DictToDotNotation(d)
print(obj.a)
print(obj.b)
print(obj["a"])
# one
# two
# Traceback (most recent call last):
#   File "<stdin>", line 10, in <module>
# TypeError: 'DictToDotNotation' object is not subscriptable

So, I want something in between. A hybrid type of sorts.

Overriding default behavior

Python exposes most its internal workings to the developer. All unders and dunders are free to override in subclasses, which will help out here quite a bit.

class DictHybrid(object):
    """
    A dict-like object used to allow both dot and array notation to access its keys.
    Accessing an undefined key using dot notation returns `None`, while using
    traditional notation `[key]` will raise a `KeyError`.
    """

    # TODO: Can add default_data here too as a ChainMap to allow for values
    # overridden by parent templates
    def __init__(self, **kwargs):
        self._dict = dict(**kwargs)

    def __getattr__(self, name):
        """Support dot notation value access"""
        return self._dict.get(name)

    def __getitem__(self, name):
        """Support dict style value access"""
        return self._dict[name]


d = DictHybrid(a="foo")
print(d.a)
print(d.b)
print(d["b"])
# foo
# None
# Traceback (most recent call last):
#   File "<stdin>", line 25, in <module>
#   File "<stdin>", line 19, in __getitem__
# KeyError: 'b'

If you want to define other behaviors for dot and dict notation, it’s very straight forward to do so. E.g. if you want to raise KeyErrors for dot notation as well.

When I figured this out, I finally closed the gap between dict and namedtuple, something that has been bothering me for a long time.

Please note that I have not implemented setters in my implementation.

Existing solutions

After looking around for similar implementations, I found a great post on StackOverflow. I advised you to go there for some great alternatives, including setters.

References

If you have any comments or feedback, please send me an e-mail. (stig at stigok dotcom).

Did you find any typos, incorrect information, or have something to add? Then please propose a change to this post.

Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.