Alan Johnstone
Alan Johnstone

Reputation: 545

when can I use dot notation to access a dictionary in Python

I am modifying somebody's code in the context of the 'gym' environment and came across the use of dot notation to access a dictionary. The following snippet shows that the dictionary in 'gym' can use the notation, but when I duplicate it, it throws an error.

import gym
env = gym.Env
env = make('connectx', debug=True)
config = env.configuration
print(config)
print(config.timeout)
dct = {'timeout': 5, 'columns': 7, 'rows': 6, 'inarow': 4, 'steps': 1000}
print(dct.timeout)

this provides the following output:

{'timeout': 5, 'columns': 7, 'rows': 6, 'inarow': 4, 'steps': 1000}
5

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
   <ipython-input-45-674d59d34c55> in <module>
      6 print(config.timeout)
      7 dct = {'timeout': 5, 'columns': 7, 'rows': 6, 'inarow': 4, 'steps': 1000}
----> 8 print(dct.timeout)

AttributeError: 'dict' object has no attribute 'timeout'

I am using Python 3. Can somebody explain please? Thanks

Upvotes: 4

Views: 10493

Answers (3)

m-sarabi
m-sarabi

Reputation: 2285

You can create a custom dictionary class that supports dot notation. You can subclass the built-in dict class and override the __getattr__, __setattr__, and __delattr__ methods. This will allow you to set, access, and delete dictionary items while retaining the usual dictionary behavior:

class DotDict(dict):
    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(f"'DotDict' object has no attribute '{key}'")

    def __setattr__(self, key, value):
        self[key] = value

    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError:
            raise AttributeError(f"'DotDict' object has no attribute '{key}'")


my_dict = DotDict(name='John', age=30)
print(my_dict)  # {'name': 'John', 'age': 30}
print(my_dict.name)  # John

# Delete a key with dot notation
del my_dict.age
print(my_dict)  # {'name': 'John'}

# Create a dictionary
new_dict = DotDict({'name': 'John', 'age': 30})
print(new_dict)  # {'name': 'John', 'age': 30}

We can extend this for nested dictionaries even further by modifying the DotDict class to recursively convert nested dictionaries into DotDict instances:

class DotDict(dict):
    def __init__(self, *args, **kwargs):
        super(DotDict, self).__init__(*args, **kwargs)
        for key, value in self.items():
            if isinstance(value, dict):
                self[key] = DotDict(value)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(f"'DotDict' object has no attribute '{key}'")

    def __setattr__(self, key, value):
        self[key] = value

    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError:
            raise AttributeError(f"'DotDict' object has no attribute '{key}'")


my_dict = DotDict({'user': {'name': 'John', 'birth': {'month': 'june', 'day': 8}}})

print(my_dict.user.birth)  # {'month': 'june', 'day': 8}
print(my_dict.user.birth.month)  # june

I published the package dotmapdict which simplifies the whole process. You can install it with:

pip install dotmapdict

Upvotes: 0

Sumukh Barve
Sumukh Barve

Reputation: 1444

Unlike JavaScript objects, Python dicts don't natively support dot notation.

Try Dotsi, Addict or a similar library. Here's a quick snippet of Dotsi in action:

>>> import dotsi
>>> 
>>> d = dotsi.Dict({"foo": {"bar": "baz"}})     # Basic
>>> d.foo.bar
'baz'
>>> d.users = [{"id": 0, "name": "Alice"}]      # In list
>>> d.users[0].name
'Alice'
>>> 

Disclosure: I'm Dotsi's author.

Upvotes: 5

Phoenixo
Phoenixo

Reputation: 2113

In python you cannot access a dictionnary value with dict.key, you need to use dict[key]

Example :

d = {"foo": 2}
print(d["foo"])
# 2

key = foo
print(d[key])
# 2

print(d.foo)
# AttributeError: 'dict' object has no attribute 'foo'

print(d.key)
# AttributeError: 'dict' object has no attribute 'key'

If you really want to use the dot notation, you can use a class (your config is probably a class instance by the way):

class MyClass():
    def __init__(self):
        self.foo = "bar"

a = MyClass()
print(a.foo)
# bar

Upvotes: 2

Related Questions