Issue with Nested Dictionaries in Python - python

I have some dictionary a.
a = {1: 'a', 2: 'b'}
And I had some dictionary b with a as a value
b = {1: a}
If I print b, change a then print b again, for example:
print(b)
a[1] = 'd'
print(b)
I get the following:
{'a': {1: 'a', 2: 'b'}}
{'a': {1: 'd', 2: 'b'}}
Why does this happen? Does the dict automatically update if you set a value to a variable and then update it? Thanks.

If you write,
b = {1: a}
the value of 1, that is a, refers to the dictionary that you previously defined. So whatever change that you make to dictionary a will be reflected in dictionary b. The literal a in dictionary b is just a reference object to dictionary a.

a, a dict, holds reference to the dictionary {1: 'a', 2: 'b'}. any changes that you make reflect in the dictionary.
since everything in python is an object, implies that every variable
is just a reference.
Hence due to the change in dict after the first print(b) the second print(b) is different.

Related

Appending Dictionaries to a Python List: Strange Result?

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.

Merge two dictionaries with keys only from the first dict

I want to merge two dictionaries so that the resulting dict has keys from the first dict and values from the first and second.
>>> A = {'AB': 'a', 'A': 'a'}
>>> B = {'AB': 'b', 'B': 'b'}
>>> merge_left(A, B)
{'AB': 'b', 'A': 'a'}
This is somewhat similar to a left outer join used in merging database tables in that one side is used as the "base" and the other side is compared to it.
Here is a table of what value each key should have in the resulting dict.
Possible Situations
Key in A
Key not in A
Key in B
Use B's value
Don't include
Key not in B
Use A's value
N/A
Is there a function merge_left or something similar that returns the dict above?
I used dict.get's ability to return a default value to make a fairly short merge_left function. This uses a dict-comprehension over key, value pairs of the first dict and checks them against the second.
def merge_left(defaults, override):
return {key, override.get(key, default) for key, default in defaults.items()}
Since this function is just returning a dict-comprehension, you can "inline" it directly into your code.
>>> A = {'AB': 'a', 'A': 'a'}
>>> B = {'AB': 'b', 'B': 'b'}
>>> {k: B.get(k, a) for k, a in A.items()}
{'AB': 'b', 'A': 'a'}

Match two dict and change keys in first if keys exists in second

I have two dict:
a={'a':'A','b':'B'}
b={'a':123,'b':123}
I need check if keys 'a' and 'b' (two elements in example, in real code, it will be more) in dict b, exist in dict a. If so, I should change the keys in dict b using values from dict a:
Expected result:
b={'A':123, 'B': 123}
How I can do it?
{a[k] if k in a else k: v for k, v in b.items()}
This is how it's done:
a={'a':'A','b':'B'}
b={'a':123,'b':123}
c = {}
for key in a.keys():
if key in b.keys():
c.update({a[key]:b[key]})
The other answers so far ignore the question which wants the code to:
change keys in dict in b for values from dict a
I infer that any data in b, for which there isn't a replacement key in a, should be left alone. So walking the keys of a creating a new dictionary c won't work. We need to modify b directly. A fun way to do this is via the pop() method which we normally associate with lists but also works on dictionaries:
a = {'a': 'A', 'b': 'B'}
b = {'a': 123, 'b': 124, 'C': 125}
for key in list(b): # need a *copy* of old keys in b
if key in a:
b[a[key]] = b.pop(key) # copy data to new key, remove old key
print(b)
OUTPUT
> python3 test.py
{'C': 125, 'A': 123, 'B': 124}
>

Insertion order and Duplicate Keys in Dictionary

I'm using python 3.7.
I have a dictionary something like this.
dict = { 'a' :2 , 'a' :1 , 'b':3 , 'c':4}
print(dict)
O/P ={'a' : 1 , 'b' :2 , 'c':3 }
Now In python 3.7 dictionary must maintain insertion order .So expected o/p will be {'a':2 , 'b':3 , 'c' :4} , but ('a',2) is being removed from dictionary instead of('a',1) .Why is this happening ??Is there any rule for removing duplicate keys in python ??
From the Python documentation:
The main operations on a dictionary are storing a value with some key and extracting the value given the key. It is also possible to delete a key:value pair with del. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key.
See: https://docs.python.org/3/tutorial/datastructures.html
Maintaining insertion order is concerned with different keys:
>>> dct = {'a': 1, 'b': 2} # do NOT shadow built-in name 'dict'
>>> print(dct)
{'a': 1, 'b': 2}
# and not
{'b': 2, 'a': 1} # which was totally possible before Python3.6
When receiving multiple values for the same key, the last one provided wins:
>>> dct = {'a': 3, 'a': 1, 'b': 2}
>>> print(dct)
{'a': 1, 'b': 2}
This is similar to the following scenario:
>>> dct = {}
>>> dct['a'] = 3
>>> dct['a'] = 1
>>> dct['b'] = 2
Would you expect dct['a'] to be 3 now because of the "insertion order"? Certainly not!
The value assigned to a key can be anything and even duplicated since it merely a value. Keys however, are similar to a variable name. Like in many programming languages, if a variable name is used again in the same scope or method, the first variable and its value is overwritten by the second since it is more recent.
In this case it may be more appropriate to to assign a different key (think of keys as identifiers) to the same value if that is your wish. Like this
dict = { 2: 'a', 1: 'a', 3:'b', 4:'c'}
print(dict)
O/P = {1: 'a', 2: 'a', 3: 'b', 4: 'c'}

Python: Dictionary changing

For some reason when I modify mydict2 it changes the contents of mydict
Here is my code:
mydict = {1:'a', 2:'b'}
mydict2 = mydict
mydict2[1] = 'c'
print(mydict2)
If you try this, it outputs {1: 'c', 2: 'b'}
It should output {1: 'a', 2: 'b'} and when you do print(mydict) it should output {1: 'c', 2: 'b'}
mydict and mydict2 are both pointing to the same object in memory. When either one changes, the other does as well. They references to the same dictionary.
It is not enough to use the assignment operator to make a proper copy. If you want mydict2 to point to a copy of the dictionary mydict points to, you need to tell Python to explicitly make a copy:
>>> mydict = {1:'a', 2:'b'}
>>> mydict2 = mydict.copy()
>>> mydict2[1] = 'c'
>>> mydict
{1: 'a', 2: 'b'}
>>> mydict2
{1: 'c', 2: 'b'}
>>>
Note however that this method will fail if you have a nested dictionary structure. You'd need to use copy.deepcopy() in that case.
mydict and mydict2 are both references to the same object.
So changes to mydict or mydict2 will change the same object, and therefore it looks like changing one of them is changing the other.
You are setting mydic2 equal to the object mydict. When you mutate mydict2, it will change the contents of mydict1.
Try using copy or copy.deepcopy as seen here: python docs
See this thread for an example: stackoverflow thread
You should use function copy:
from copy import copy
mydict = {1:'a', 2:'b'}
mydict2 = copy(mydict)
mydict2[1] = 'c'
print(mydict2)
There are two links for the same object. If you want to have two objects, you should copy your dict
mydict and mydict2 both reference the same dictionary, so when you change one, you change the other one too.

Categories

Resources