I recently came across a strange observation while creating list of dictionaries by appending dictionaries to a list.
Below is my code:
a = []
for i in range(5):
m = {'a':'apple'}
a.append(m)
m['b'] = 'ball'
for i in a:
print(i)
I expected that the list a will only contain 'a': 'apple' as the key b is defined after the append statement.
Suprisingly, below is the output I obtained:
{'a': 'apple', 'b': 'ball'}
{'a': 'apple', 'b': 'ball'}
{'a': 'apple', 'b': 'ball'}
{'a': 'apple', 'b': 'ball'}
{'a': 'apple', 'b': 'ball'}
Why does this happen? Thanks in advance!
That's because 2 things in python:
dict in python is a mutable object. In your code, the m is a dict, even it's been appended to object a. Its value can still be updated after that. This will affect the value been appended to a too.
function parameter is always assigned by Reference in python. In code a.append(m), you are not passing m's value to append() but m's reference. So when you update m's value, a's value will be updated as well.
I suggest you can study the mutable and immutable objects in python further.
Related
Is it correct to say that the rightmost/last key-value pair for a given key would always be considered if there are multiple identical keys when initializing a dictionary ?
Example :
Dict = {'A': 5, 'B': 6, 'A': 10}
Will Dict['A'] always be 10 in all python implementations? Where does python enforce this ?
You know that python dict can't contain duplicate keys. So
Dict = {'A': 5, 'B': 6)
Dict.update({'A': 10})
print(Dict['A'])
will result in the last value assigned to the key A:
Output:
10
So the situation is almost like that, python goes through the dictionary during evaluation, and keeps the last value assigned to the keys.
I know dict aren't ordered, but:
That doesn't mean python will jump back and forth on the dict when parsing the dict into memory.
It will parse through it from left to right to get the collect the data, but it stores the dict without keeping its order.
Python dict can not have duplicate keys. if you try to add the same key again, it will update the existing key with the new value.
Dict = {'A': 5, 'B': 6, 'A': 10}
print(Dict)
{'A': 10, 'B': 6}
the above statement execution is similar to below:
Dict['A'] = 5
print(Dict)
{'A'=5}
Dict['B'] = 6
print(Dict)
{'A'=5, 'B'=6}
Dict['A'] = 10
print(Dict)
{'A'=10, 'B'=6}
This is the code:
def appd():
atho = []
data = {'snm':None}
for i in range(5):
data['snm'] = i
atho.append(data)
return atho
I expect that the result will be like this:
[{'snm': 0}, {'snm': 1}, {'snm': 2}, {'snm': 3}, {'snm': 4}]
but the result I got in python 3 platform is:
[{'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}, {'snm': 4}]
How does that happen?
A dictionary cannot have identical keys. So, every time you are doing data['snm'] = i you are replacing the value. Also, your append adds the same dictionary every time, not a copy. So, you list does not have 5 dictionaries, it has 5 references to the same dictionary. And, when it changes, all positions of your list change.
Short fix: add a new dict every time
for i in range(5):
atho.append({'snm': i})
Dictionary cannot hold duplicate keys. If you try adding duplicates, the last added value is added to the key.
>>> d = {'a': 1}
>>> d['a'] = 2
>>> d['a'] = 3
>>> d
{'a': 3}
>>>
With data['snm'] = i, you are basically doing the same thing and this dictionary is being added to list using append.
To fix it, define data = {} inside your loop, so every time you create a new dictionary before appending.
def appd():
atho = []
for i in range(5):
data = {}
data['snm'] = i
atho.append(data)
return atho
print(appd())
You are inserting the same dictionary again and again, instead of inserting a new dictionary whose key is snm.
On each iteration of the range, you are updating the value of the dictionary, therefore it gets updated for all the elements in the list, because all of them point to the same dictionary instance.
You must create a new dictionary on each iteration and then insert it.
Try this:
def appd():
atho = []
for i in range(5):
atho.append({'snm':i})
return atho
If you reuse the same oject, again and again, you are simply updating it's contents. The trick is either to explicitly copy the object or create a new one. You cannot simply keep overriting the same key and expect different values
You are actually appending a reference to the original dictionary.
The result you are seeing is the last iteration of your loop updating the dictionary, and thus all its references in your list.
Using atho.append(data.copy()) will work.
I cannot rename the Python dict using pop as described below. I've used suggestions from this post. Is this a Python bug? I'm using Python 3.5.2
>>> d = {'a': 'ABC', 'b': 'CDE', 'c': 'KRT'}
>>> for old_key in d.keys():
d['NEW_KEY_' + old_key] = d.pop(old_key)
>>> d
{'NEW_KEY_NEW_KEY_NEW_KEY_b': 'CDE', 'NEW_KEY_NEW_KEY_a': 'ABC', 'c': 'KRT'}
In Python 3, you have to change for old_key in d.keys() into for old_key in list(d.keys()). That should work because you are iterating over a dynamic entity.
It's mentioned in the documentation that changing a dictionary while iterating over it might fail to produce correct results. You'd better write something like
new_dict = {'NEW_KEY_' + key: value for key, value in old_dict.items()}
You are changing your keys as you iterate over a view of them. That's not recommended.
Instead, you can take a copy of your keys and iterate over them. Since dictionary keys are unique, you can use list or set:
d = {'a': 'ABC', 'b': 'CDE', 'c': 'KRT'}
for old_key in list(d):
d['NEW_KEY_' + old_key] = d.pop(old_key)
# {'NEW_KEY_a': 'ABC', 'NEW_KEY_b': 'CDE', 'NEW_KEY_c': 'KRT'}
You can, of course, use a dictionary comprehension, which you should find more efficient.
When i do this on python i update all keys in one time.
>>> base = {}
>>> keys = ['a', 'b', 'c']
>>> base.update(dict.fromkeys(keys, {}))
>>> base.get('a')['d'] = {}
>>> base
{'a': {'d': {}}, 'c': {'d': {}}, 'b': {'d': {}}}
>>> map(id, base.values())
[140536040273352, 140536040273352, 140536040273352]
If instead of .get i use [] operator this not happen:
>>> base['a']['d'] = {}
>>> base
{'a': {'d': {}}, 'c': {}, 'b': {}}
Why?
When you initialize the value for the new keys as {} a new dictionary is created and a reference to this dictionary is becoming the values. There is only one dictionary and so if you change one, you will change "all".
I tried it with both Python 2.7.6 and 3.4.3. I get the same answer when either get('a') or ['a'] is used. Appreciate if you can verify this at your end. Python does object reuse. Thus, dict.fromkeys() reuses the same empty dict is to initialize. To make each one a separate object, you can do this:
base.update(zip(keys, ({} for _ in keys)))
The code:
>>> mydict = {}
>>> keylist = ['a','b','c']
>>> mydict=dict.fromkeys(keylist,{})
>>> mydict['a']['sample'] = 1
>>> mydict
{'a': {'sample': 1}, 'c': {'sample': 1}, 'b': {'sample': 1}}
I was expecting mydict['a']['sample'] = 1 would set the value just for a's dictionary value and would get this: {'a': {'sample': 1}, 'c': {}, 'b': {}}.
What am I missing here? What should I have to do to get the expected output?
The problem is that you added the same dictionary to mydict for every key. You want to add different dictionaries, like so:
mydict = dict((key, {}) for key in keylist)
In the above code, you create a new dictionary to pair with each key. In your original code, the function fromkeys took the argument (the empty dictionary you provided) and added that exact argument - that single empty dictionary you created to pass in to the function - to each of the keys. When that one dictionary was changed, then, that change showed up everywhere.