Tos
Tos

Reputation: 67

python dictionary creation in for loop

I try to create a dictionary which will have a relations to different sides taken from the list.

import collections
def create_dict(sides = ["A", "B", "C"]):
    my_dict = dict.fromkeys(sides, {})
    print("my_dict created here: ", my_dict)
    for k in sides:
        remining_list = collections.deque(sides)
        remining_list.remove(k)
        my_dict[k]["relation"] = dict.fromkeys(remining_list, 0)
    return my_dict

The dict is created with empty dictionaries: ('my_dict created here: ', {'A': {}, 'C': {}, 'B': {}}) I expect an output as:

{'A': {'relation': {'B': 0, 'C': 0}},
 'B': {'relation': {'A': 0, 'C': 0}},
 'C': {'relation': {'A': 0, 'B': 0}}}

but instead each value of inner dictionary comes to the last processed dictionary like this:

{'A': {'relation': {'A': 0, 'B': 0}},
 'C': {'relation': {'A': 0, 'B': 0}},
 'B': {'relation': {'A': 0, 'B': 0}}}

Can not figure out in which step I do wrong. When I loop over the keys I give it as a value only to this particular key not to all as in the output. Also is there any more efficient way to create this dictionary?

for completes this is example of call:

if __name__=="__main__":
    my_dict = create_dict()
    print(my_dict)

Upvotes: 0

Views: 100

Answers (2)

Perkins
Perkins

Reputation: 2517

Check the doc on dict.fromkeys. All the keys in the returned dict share the same value. You need a constructor that uses a factory, instead of a value.

Try my_dict = {i:{} for i in sides}.

For the complete solution, I'd use a nested version.

def create_dict(sides):
    return {i:dict(relation={j:0 for j in sides if j!=i}) 
               for i in sides}

Note that if order matters, the above only works on CPython 3.6 or later, or any conformant python 3.7 or later. You could use OrderedDict in earlier versions, but it has performance penalties.

Also note that it is generally considered bad form to use lists or other mutable types in default arguments, so you probably want

def create_dict(sides=("A", "B", "C")):
    ...

instead.

Upvotes: 3

Dani Mesejo
Dani Mesejo

Reputation: 61930

Since you are using collections already, I suggest you use defaultdict:

import collections


def create_dict(sides=["A", "B", "C"]):
    my_dict = collections.defaultdict(dict)
    for k in sides:
        remining_list = collections.deque(sides)
        remining_list.remove(k)
        my_dict[k]["relation"] = dict.fromkeys(remining_list, 0)
    return dict(my_dict.items())


print(create_dict())

Output

{'A': {'relation': {'B': 0, 'C': 0}}, 'B': {'relation': {'A': 0, 'C': 0}}, 'C': {'relation': {'A': 0, 'B': 0}}}

Upvotes: 0

Related Questions