When we write a class in Python, how do we do it if some of the member variables need to be named and assigned with a dictionary? This scenario is most common when reading a dictionary variable from a file (such as json, npz, etc.) into memory and assigning it to a class member variable, or an instance variable that has been generated.

Defining member variables with dict

The method __dict__.update() is supported directly in python to avoid the use of locals(), vars() and eval() functions, so we can look directly at a case like this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
In [1]: dict_a = {'a':1, 'b':2}

In [2]: dict_b = {'c':3}

In [3]: class D(object):
   ...:     def __init__(self):
   ...:         self.d = 4
   ...:         self.__dict__.update(dict_a)
   ...:         self.__dict__.update(dict_b)
   ...: 

In [4]: new_D = D()

In [5]: new_D.__dict__
Out[5]: {'d': 4, 'a': 1, 'b': 2, 'c': 3}

In [6]: new_D.a
Out[6]: 1

In [7]: new_D.c
Out[7]: 3

In this case, we have defined two dictionaries dict_a and dict_b outside of the class, and the key values of the dictionaries are in string format. And we know that string format can’t be used directly as variable name in python without using eval. After importing the dictionary by __dict__.update() method, all the key and value values will be automatically recognized and assigned to the current class as member variables. However, one disadvantage of this method is that it can only be assigned by a single-level dictionary. If you encounter a dictionary with a hierarchy, it will not automatically distinguish the hierarchy for assignment, such as the code below.

1
2
3
4
5
6
In [15]: dict_a = {'f':{'h':8},'g':7}

In [16]: new_D = D()

In [17]: new_D.__dict__
Out[17]: {'d': 4, 'f': {'h': 8}, 'g': 7, 'c': 3}

Nested dictionaries to member variables

According to this particular scenario mentioned at the end of the previous section, we need to recursively add the elements within the dictionary, and if we encounter a nested dictionary element, we recursively add that element to the member variable at the next level, as shown in the following code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
dict_a = {'f':{'h':8},'g':7}
dict_b = {'c':3}

class D:
    def __init__(self, *args):
        for arg in args:
            for k, v in arg.items():
                if isinstance(v, dict):
                    self.__dict__[k] = D(v)
                else:
                    self.__dict__[k] = v

new_D = D(dict_a, dict_b)
print (new_D.__dict__)
print (new_D.f.h)

The final output is shown below.

1
2
3
{'f': <__main__.D object at 0x7fd2f32a4340>
, 'g': 7, 'c': 3}
8

As you can see, we finally managed to read the value of the original nested dictionary by using the new_D.f.h method. although this writing method does not look very elegant, there seems to be no better solution. And, by practicing this small problem, I found another slightly interesting problem: when updating a dictionary type in python, if the key has a dot in the string, such as parDict['group1.b'] = 3, it can only be updated by such a string, if you use parDict.update( group1.b=4) then an error will occur, this is because the dot is not an identifier in python and cannot be used for naming, the original content is as follows.

The valid characters for identifiers are the same as in Python 2.x: the uppercase and lowercase letters A through Z, the underscore _ and, except for the first character, the digits 0 through 9.

Summary

The problem scenario addressed in this article is this: given a dictionary, for example, the data loaded from a json file or an npz file is a dictionary data structure, if we want to assign this dictionary to a class and make the dictionary key and value as member variable names and member variable values of the class, how do we do it? For a flat dictionary (no nested dictionaries), we can directly use update to transform all the keys and values of the dictionary into member variables of the current class. What is more problematic is a hierarchical dictionary with nested dictionaries, where we can only use a loop and recursively assign values to the class member variables.