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
Python: Why Is Functools.Partial Necessary
Get Ip Address of Visitors Using Flask for Python
Dictionary: Get List of Values for List of Keys
Python Regex Matching Unicode Properties
Pyqt: Connecting a Signal to a Slot to Start a Background Operation
Comparing Two Numpy Arrays for Equality, Element-Wise
Convert Array of Indices to One-Hot Encoded Array in Numpy
Plotting in a Non-Blocking Way with Matplotlib
Python Recursion with List Returns None
How to Run Multiple While Loops at a Time in Pygame
Python App Does Not Print Anything When Running Detached in Docker
Python Pandas Insert List into a Cell
Why Doesn't Pygame Draw in the Window Before the Delay or Sleep
Plotting with Seaborn Using the Matplotlib Object-Oriented Interface
Unicodedecodeerror: 'Utf8' Codec Can't Decode Byte 0Xa5 in Position 0: Invalid Start Byte