Trying to change dictionary keys from strings to integers and get this error: RuntimeError: dictionary keys changed during iteration
Question:
def load_method(self, inp_list, file):
self.DB.global_row = -1
# clear the widgets and listbox
self.DB.clear_test_list()
for item in self.DB.inp_dict:
del item
inp_list.delete(0, 'end')
# THIS IS THE RELEVANT PART FOR THIS QUESTION
[self.DB.test_dict, self.DB.inp_dict] = json.load(file)
counter = 0
for key in self.DB.test_dict: # change the keys to be integer instead of strings
self.DB.test_dict[counter] = self.DB.test_dict[key]
del self.DB.test_dict[key]
counter += 1
I’m sure there is a correct way to do it, does anyone know how?
Answers:
You cannot neither modify nor remove/add keys to a dictionary while iterating over it.
A dict comprehension seems to be the best choice for your use case:
- use
zip
to get values from the range you want (looks like [0,len(self.DB.test_dict)), where 0 is inclusive and the last element exclusive)
self.DB.test_dict = {counter : v for (k,v), counter in zip(self.DB.test_dict.items(), range(len(self.DB.test_dict)))}
Example:
>>> x = {"a": 1, "b":2}
>>> x = {int(counter):v for (k,v),counter in zip(x.items(), range(len(x)))}
>>> x
{0: 1, 1: 2}
You’d have to create a new dictionary from your existing one. A simple pythonic way of achieving this would be by changing the code as follows:
def load_method(self, inp_list, file):
self.DB.global_row = -1
# clear the widgets and listbox
self.DB.clear_test_list()
for item in self.DB.inp_dict:
del item
inp_list.delete(0, 'end')
# THIS IS THE RELEVANT PART FOR THIS QUESTION
[self.DB.test_dict, self.DB.inp_dict] = json.load(file)
self.DB.test_dict = {int(idx): self.DB.test_dict[key] for idx, key in enumerate(d.keys())}
def load_method(self, inp_list, file):
self.DB.global_row = -1
# clear the widgets and listbox
self.DB.clear_test_list()
for item in self.DB.inp_dict:
del item
inp_list.delete(0, 'end')
# THIS IS THE RELEVANT PART FOR THIS QUESTION
[self.DB.test_dict, self.DB.inp_dict] = json.load(file)
counter = 0
for key in self.DB.test_dict: # change the keys to be integer instead of strings
self.DB.test_dict[counter] = self.DB.test_dict[key]
del self.DB.test_dict[key]
counter += 1
I’m sure there is a correct way to do it, does anyone know how?
You cannot neither modify nor remove/add keys to a dictionary while iterating over it.
A dict comprehension seems to be the best choice for your use case:
- use
zip
to get values from the range you want (looks like [0,len(self.DB.test_dict)), where 0 is inclusive and the last element exclusive)
self.DB.test_dict = {counter : v for (k,v), counter in zip(self.DB.test_dict.items(), range(len(self.DB.test_dict)))}
Example:
>>> x = {"a": 1, "b":2}
>>> x = {int(counter):v for (k,v),counter in zip(x.items(), range(len(x)))}
>>> x
{0: 1, 1: 2}
You’d have to create a new dictionary from your existing one. A simple pythonic way of achieving this would be by changing the code as follows:
def load_method(self, inp_list, file):
self.DB.global_row = -1
# clear the widgets and listbox
self.DB.clear_test_list()
for item in self.DB.inp_dict:
del item
inp_list.delete(0, 'end')
# THIS IS THE RELEVANT PART FOR THIS QUESTION
[self.DB.test_dict, self.DB.inp_dict] = json.load(file)
self.DB.test_dict = {int(idx): self.DB.test_dict[key] for idx, key in enumerate(d.keys())}