Last updated: Apr 9, 2024
Reading timeยท5 min

To use dot notation to access dictionary keys:
dict class when defining a class.__getattr__ method to dict.__getitem__.dict.__getitem__ allows us to use dot
notation to access dictionary keys.class AttributeDict(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ my_dict = {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} new_dict = AttributeDict(my_dict) print(new_dict.website) # ๐๏ธ bobbyhadz.com print(new_dict.topic) # ๐๏ธ Python new_dict.author = 'Borislav Hadzhiev' # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python', 'author': 'Borislav Hadzhiev'} print(new_dict) del new_dict.author # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} print(new_dict)

The AttributeDict class extends the built-in dict class.
__getattr__ method to dict.__getitem__ to access a dictionary's keys as attributes.The
__getattr__
method is called when the default attribute access fails with an
AttributeError.
In other words, __getattr__() gets called only for attributes that don't
exist.
dict.__getitem__ method is called when we access a dictionary key using square brackets, e.g. my_dict['name'] calls my_dict.__getitem__('name').We set the __getattr__ method in the AttributeDict class to
dict.__getitem__, so any time the user tries to access an attribute that
doesn't exist, the dict.__getitem__ method is called.
We used the same approach to be able to use dot notation when setting and deleting keys from the dictionary.
class AttributeDict(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ my_dict = {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} new_dict = AttributeDict(my_dict) # โ Add a key to the dictionary new_dict.author = 'Borislav Hadzhiev' # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python', 'author': 'Borislav Hadzhiev'} print(new_dict) # โ delete a key from the dictionary del new_dict.author # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} print(new_dict)
The object.__setattr__ method is called when an attribute assignment is attempted.
We set the method to dict.__setitem__ which is called when a key is added to a dictionary.
my_dict['key'] = 'value' calls my_dict.__setitem__('key', 'value').The
object.__delattr__
method is called when an attribute is deleted using the del operator.
We set the method to dict.__delitem__ which is called when the user deletes a key from a dictionary.
del my_dict['key'] calls my_dict.__delitem__('key') under the hood.The dict.__getitem__ method raises a KeyError when we access a key that
doesn't exist in the dictionary.
If you'd rather return None for non-existent keys, set __getattr__ to
dict.get.
class AttributeDict(dict): __getattr__ = dict.get __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ my_dict = {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} new_dict = AttributeDict(my_dict) print(new_dict.example) # ๐๏ธ None print(new_dict.website) # ๐๏ธ bobbyhadz.com print(new_dict.topic) # ๐๏ธ Python

The dict.get() method returns the value for the given key if the key is in the dictionary, otherwise a default value is returned.
The method takes the following 2 parameters:
| Name | Description |
|---|---|
| key | The key for which to return the value |
| default | The default value to be returned if the provided key is not present in the dictionary (optional) |
If a value for the default parameter is not provided, it defaults to None,
so the get() method never raises a KeyError.
Alternatively, you can use the __dict__ attribute.
This is a three-step process:
dict class when defining a class.dict class in your user-defined class.__dict__ attribute to the current instance.class AttributeDict(dict): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__dict__ = self my_dict = {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} new_dict = AttributeDict(my_dict) print(new_dict.website) # ๐๏ธ bobbyhadz.com print(new_dict.topic) # ๐๏ธ Python # โ add a key to the dictionary new_dict.author = 'Borislav Hadzhiev' # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python', 'author': 'Borislav Hadzhiev'} print(new_dict) # โ delete a key from the dictionary del new_dict.author # ๐๏ธ {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} print(new_dict)
The first line in the class's
__init__() method runs
the constructor of the dict class with the provided arguments. By doing this,
our AttributeDict class behaves like a dictionary.
The self.__dict__ = self line sets the __dict__ attribute to the current
instance.
__dict__ attribute returns a dictionary containing the object's properties and values.In our case, the __dict__ attribute points to a subclass of dict that allows
for attribute access.
Something to note when using this approach is that when you use dot notation to
access a key that is not present in the dictionary, an AttributeError is
raised instead of a KeyError.
class AttributeDict(dict): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__dict__ = self my_dict = {'id': 1, 'website': 'bobbyhadz.com', 'topic': 'Python'} new_dict = AttributeDict(my_dict) # โ๏ธ AttributeError: 'AttributeDict' object has no attribute 'example' print(new_dict.example)
If you need to access nested dictionary keys as attributes, use the class from the next code snippet.
To use dot notation to access nested dictionary keys:
__init__ method of a class.dict, instantiate the class with the value.class Struct: def __init__(self, **kwargs): for key, value in kwargs.items(): if isinstance(value, dict): self.__dict__[key] = Struct(**value) else: self.__dict__[key] = value my_dict = { 'name': { 'first': 'bobby', 'last': 'hadz', }, 'website': 'bobbyhadz.com' } obj = Struct(**my_dict) print(obj.name.first) # ๐๏ธ bobby print(obj.name.last) # ๐๏ธ hadz print(obj.website) # ๐๏ธ bobbyhadz.com
The Struct class takes keyword arguments and uses the __dict__ attribute on
the object to
convert the nested dictionary to an object.
Struct class.If the key doesn't point to a nested dictionary, we add it to the __dict__
attribute.
You can access nested attributes on the object using dot notation.
If you try to access an attribute that is not present on the object, an
AttributeError is raised.
I've also written an article on how to use a variable to access a dictionary key.
You can learn more about the related topics by checking out the following tutorials: