Using dot "." notation to access dictionary keys in Python

avatar

Borislav Hadzhiev

Last updated: Sep 16, 2022

banner

Photo from Unsplash

Using dot "." notation to access dictionary keys in Python #

To use dot notation to access dictionary keys:

  1. Extend the dict class when defining a class.
  2. Set the __getattr__ method to dict.__getitem__.
  3. Redirecting attribute access to dict.__getitem__ allows us to use dot notation to access dictionary keys.
main.py
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.

We set the __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.

The 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.

main.py
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.

For example, 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.

For example, 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.

main.py
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:

NameDescription
keyThe key for which to return the value
defaultThe 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.

Use dot "." notation to access dictionary keys using __dict__ #

To use dot notation to access dictionary keys:

  1. Extend the dict class when defining a class.
  2. Call the constructor of the dict class in your user-defined class.
  3. Set the __dict__ attribute to the current instance.
main.py
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.

By default, the __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.

main.py
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.

Use dot "." notation to access nested dictionary keys #

To use dot notation to access nested dictionary keys:

  1. Iterate over the dictionary's items in the __init__ method of a class.
  2. If the key has a value of type dict, instantiate the class with the value.
  3. Otherwise, set the key to the value.
main.py
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.

On each iteration, we check if the current key points to a dictionary and if it does, we recursively pass the dictionary to the 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 wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.