Dictionary Creation with Fromkeys and Mutable Objects. a Surprise

Dictionary creation with fromkeys and mutable objects. A surprise

Your Python 2.6 example is equivalent to the following, which may help to clarify:

>>> a = []
>>> xs = dict.fromkeys(range(2), a)

Each entry in the resulting dictionary will have a reference to the same object. The effects of mutating that object will be visible through every dict entry, as you've seen, because it's one object.

>>> xs[0] is a and xs[1] is a
True

Use a dict comprehension, or if you're stuck on Python 2.6 or older and you don't have dictionary comprehensions, you can get the dict comprehension behavior by using dict() with a generator expression:

xs = dict((i, []) for i in range(2))

python dictionary in dictionary changing value

The wins dictionary is shared across all keys inside the combined_data dictionary.

To resolve this issue, use a dictionary comprehension instead:

combined_data = {team: {"wins" : 0} for team in teams}

Initailizing nested dict with .fromkeys

That's because you associated all keys of the outer dictionary with the same inner dictionary. You first constructed a dictionary with dict.fromkeys(y,0), and then you associate that dictionary with all the keys with: dict.fromkeys(x,...).

A way to construct the dictionary you want is for instance dictionary comprehension:

zx = {k: dict.fromkeys(y,0) for k in x}

Although this looks quite the same it is not: here, we will for every k in x evaluate dict.fromkeys(y,0) again. As a result, the constructed dictionaries will all he equivalent, but not the same object.

Now we obtain the expected:

>>> x=[1,2,3,4,5]
>>> y=[7,8,9,10,11]
>>> zx = {k: dict.fromkeys(y,0) for k in x}
>>> zx
{1: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 2: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 3: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 4: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 5: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}}
>>> zx[1][8]+=1
>>> zx
{1: {8: 1, 9: 0, 10: 0, 11: 0, 7: 0}, 2: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 3: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 4: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}, 5: {8: 0, 9: 0, 10: 0, 11: 0, 7: 0}}

Updating dictionary in Python by key changing other keys

You can't use dict.fromkeys when the value to use with each key is mutable; it uses aliases of the same value as the value for every key, so you get the same value no matter which key you look up. It's basically the same problem that occurs with multiplying lists of lists. A simple solution is to replace the outer dict.fromkeys with a dict comprehension:

region_dict = {region: dict.fromkeys(subregions) for region in regions}

Python append to list by key issue

All of the entries in group_keys are pointing to the same list.
Try using a dictionary comprehension to create group_keys

group_keys = {x:[] for x in set(group_keys)}

add a value for a list of specific keys in dictionary

The line:

dict.fromkeys(keyList, [])

creates the same list which is shared by all keys.

Instead, explicitly create list to each key:

keyList = ['a','b','c']
testdict = { k : list() for k in keyList}
specKey = ['a','c']

for i in specKey:
testdict[i].append(i)

# {'a': ['a'], 'b': [], 'c': ['c']}
print(testdict)

Initializing dict of dict of dict with independent (unlinked) values

So the problem is the 0s (values) not the keys that I was thinking it was. This solves the issue but is there something more readable than this dictionary comprehension?

l = ['a', 'b', 'c']
d = {'CategoryA': dict((i, dict((i, 0) for i in l)) for i in l),
'CategoryB': dict((i, dict((i, 0) for i in l)) for i in l),
'CategoryC': dict((i, dict((i, 0) for i in l)) for i in l)}
d['CategoryA']['a']['c'] += 1

print d['CategoryA']['a']['c']
print d['CategoryA']['b']['c']
print d['CategoryA']['c']['c']

Prints 1 first, then 0 twice as expected.

Invert dictionary with set of values from the original dict's values

When you use fromkeys, all the keys point to the same object. In this case a list:

dict.fromkeys(set(myDict1.values()),[])

I would suggest using:

dict((k, []) for k in set(myDict1.values()))

Which would create a new list for each key.

Python nested dictionary updating all dicts rather than specified

To solve this problem replace the update function used to update the mDict variable inside the webscraper function with an = sign

#Imports
import requests
from bs4 import BeautifulSoup as bsoup

dataurls = {
'race1': 'https://fiaresultsandstatistics.motorsportstats.com/results/2022-bahrain-grand-prix/classification/2c65d50d-606e-4988-81c5-7a4976ef0e6f'
}

#Setup the dictionary
races = ['race1', 'race2']
drivers = ['driver1', 'driver2']
mainDict = dict.fromkeys(races, {})

#Scraping elements
def webscraper(mDict, race):
soup = bsoup(requests.get(dataurls[race]).content, "html.parser")
#Dict for races, will contain driver key and lap time value.
rDict = {}
#Parse the table by row, extract driver name and lap time
for tr in soup.find("table", class_="_2Q90P").find_all("tr", class_="_3AoAU"):
row = ([td.text for td in tr.find_all('td')])
dDriver = row[2]
dTime = row[6]
dDict = {dDriver: dTime}
rDict.update(dDict)
mDict[race] = rDict
webscraper(mainDict, races[0])
print(mainDict)

or change the way you are using the update:

mDict.update({race: rDict})

https://www.w3schools.com/python/ref_dictionary_update.asp

Apparently the way you are using selects all keys in the dictionary



Related Topics



Leave a reply



Submit