Access dictionary Keys as Attributes in Python

avatar

Borislav Hadzhiev

Last updated: Sep 16, 2022

banner

Photo from Unsplash

Access dictionary Keys as Attributes in Python #

To access dictionary keys as attributes:

  1. Extend the dict class in a user-defined class.
  2. Set the __getattr__ method to dict.__getitem__.
  3. Setting __getattr__ to dict.__getitem__ allows us to access dictionary keys as attributes.
main.py
class AttributeDict(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ my_dict = {'id': 1, 'name': 'Bobbyhadz', 'language': 'Python'} new_dict = AttributeDict(my_dict) print(new_dict.name) # 👉️ Bobbyhadz print(new_dict.language) # 👉️ Python new_dict.age = 30 # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': 'Python', 'age': 30} print(new_dict) del new_dict.age # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': 'Python'} print(new_dict)

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 for which an AttributeError is raised, the dict.__getitem__ method is called.

We used the same approach to implement attribute access 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, 'name': 'Bobbyhadz', 'language': 'Python'} new_dict = AttributeDict(my_dict) new_dict.age = 30 # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': 'Python', 'age': 30} print(new_dict) del new_dict.age # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': '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.

Alternatively, you can use the __dict__ attribute.

Access dictionary Keys as Attributes using __dict__ #

To access dictionary keys as attributes:

  1. Extend the dict class in a user-defined class.
  2. Call the constructor of the dict 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, 'name': 'Bobbyhadz', 'language': 'Python'} new_dict = AttributeDict(my_dict) print(new_dict.id) # 👉️ 1 print(new_dict.name) # 👉️ Bobbyhadz new_dict.age = 30 # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': 'Python', 'age': 30} print(new_dict) del new_dict['age'] # 👇️ {'id': 1, 'name': 'Bobbyhadz', 'language': '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.

If you need to access nested dictionary keys as attributes, use the class from the next code snippet.

Access nested dictionary Keys as Attributes in Python #

To access nested dictionary keys as attributes:

  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', }, 'country': 'Example' } obj = Struct(**my_dict) print(obj.name.first) # 👉️ bobby print(obj.name.last) # 👉️ hadz print(obj.country) # 👉️ Example

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.