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: