Create nested python dictionary and assign value inline? - python-3.x

I know that one can do something like this
d = {}
d['key1'] = {'Innerkey1':{'Response':'value','Type':'value2'}}
However, I need something like this
d['Key1']['Innerkey1'] = {'Response':'value','Type':'value2'}
as i'm consistently adding new innerkeys depending on various factors, and if I were to just do
d['Key1'] = {'NewInnerkey2': {'Response':'value','Type':'value2'}}
it overwrites and replaces innerkey1.
I suppose I can initialize d['key1'] first and use
.append({'NewInnerkey2': {'Response':'value','Type':'value2'}}),
however there are many different spots where a new primary or inner key may need to be initialized or not, and so it would lead to quite a bit of fluff to check if whether it's been initialized or not and etc.
Any ideas?

You can use a defaultdict
d = defaultdict(dict)
d['key1']['innerkey'] = {'Response':'value','Type':'value1'} # won't throw errors
d['key2']['innerkey2'] = {'Response':'value','Type':'value2'} # won't overwrite the value for innerkey

Related

Can't figure how to stop dictionary keys from overwriting themselves

I'm trying to create a dictionary and my dictionary keys keep overwriting themselves. I don't understand how I can handle this issue.
Here's the script:
import MDAnalysis as mda
u = mda.Universe('rps5.prmtop', 'rps5.inpcrd')
ca = u.select_atoms('protein')
charges = ca.charges
atom_types = ca.names
resnames = ca.resnames
charge_dict = {}
for i in range(len(charges)):
#print(i+1 ,resnames[i], atom_types[i], charges[i])
charge_dict[resnames[i]] = {}
charge_dict[resnames[i]][atom_types[i]] = charges[i]
print(charge_dict)
The charges, atom_types and resnames are all lists, with the same number of elements.
I want my dictionary to look like this: charge_dict[resname][atom_types] = charges (charge_dict['MET']['CA'] = 0.32198, for example).
Could you please help me with this issue?
Without actually seeing a complete problem description, my guess is that your final result is that each charge_dict[name] is a dictionary with just one key. That's not because the keys "overwrite themselves". Your program overwrites them explicitly: charge_dict[resnames[i]] = {}.
What you want is to only reset the value for that key if it is not already set. You could easily do that by first testing if resnames[i] not in charge_dict:, but the Python standard library provides an even simpler mechanism: collections.defaultdict. A defaultdict is a dictionary with an associated default value creator. So you can do the following:
from collections import defaultdict
charge_dict = defaultdict(dict)
After that, you won't need to worry about initializing charge_dict[name] because a new dictionary will automatically spring into existence when the default value function (dict) is called.

How to define a function that will convert list into dictionary while also inserting 'None' where there is no value for a key (Python3)?

Say we have a contact_list like this:
[["Joey", 30080],["Miranda"],["Lisa", 30081]]
So essentially "Miranda" doesn't have a zipcode, but with the function I want to define, I'd like it to automatically detect that and add "None" into her value slot, like this:
{
"Joey": 30080,
"Miranda": None,
"Lisa": 30081
}
So far I have this, which just converts the list to a dict:
def user_contacts(contact_list):
dict_contact = dict(contact_list)
print(dict_contact)
Not sure where I go from here, as far as writing in the code to add the None for "Miranda". Currently, I just get an error that says the 1st element ("Miranda") requires two lengths instead of one.
Eventually I want to just a pass any list like the one above in the defined function: user_contacts and, again, be able to get the dictionary above as the output.
user_contacts([["Joey", 30080],["Miranda"],["Lisa", 30081]])
so here is what you can do. you can check to see if the len of a certain element in your list, meets the expectations (in this case, 2 for name and zipcode). then if it fails the expectations, you can add "none":
contacts = [["Joey", 30080], ["Miranda"], ["Lisa", 30081]]
contacts_dict = {}
for c in contacts:
if len(c) < 2:
c.append('None')
contacts_dict.update({c[0]: c[1]})
print(contacts_dict)
and the output is:
{'Joey': 30080, 'Miranda': 'None', 'Lisa': 30081}
Try this:
def user_contacts(contact_list):
dict_contact = dict((ele[0], ele[1] if len(ele) > 1 else None) for ele in
contact_list)
print(dict_contact)

Reading and writing to a dictionary dynamically

I am trying to read value from dictionary and then write to a different one.
The following works, but is hardcoded
this_application['bounces'] = {}
this_application['bounces']['month'] = {}
this_application['bounces']['month']['summary'] = {}
try:
got_value = application.ga_data['ga:bounces']['ga:month']['summary']['recent']
except:
got_value = ""
this_application['bounces']['month']['summary']['recent'] = got_value
What I want to do though, is pass in a from and to list (as I will have lots of these).
I was imagining the input would be something like this
{"ga_data": [{"from": "ga:bounces.ga:month.summary.recent", "to": "bounces.month.summary.recent"},{"from": "ga:sessions.ga:month.summary.recent", "to": "sessions.month.summary.recent"}]}
In which case it would do the above twice (with checking for existing dictionaries etc). I am fine on the checking etc., it is how to use the above that I am stuck on.
Any help would be appreciated
Thanks
You can use defaultdict but there are some special things to consider when doing it. If you read a value that does not exist it will add an empty value to the dict.
import collections
nested_dict = lambda: collections.defaultdict(nested_dict)
d = nested_dict()
d[1][2][3] = 'Hello, dictionary!'
print(d[2]) # I read the value and thus added the key to the dict
print(d[1][2][3]) # Prints Hello, dictionary!
print(d.keys()) # Shows that [1, 2] are keys
Credit To: How can I get Python to automatically create missing key/value pairs in a dictionary?

loop through a list with a function and store as variable

I have a list of variables I need to run though a function to produce a json table. I want to loop through this list (list_db) and create a new variable to look through them manually in spyder. I am having trouble creating those new variables from the for loop. I thought i could use the name of the items in list as the new variable name, but i cant get it to work. Here is what I have:
for i in list_db:
p = str(i)
p = getDF(i) #function to run
What am I missing? What is the more standard way of doing this i cant think of?
It seems variable names don't really act how you are expecting. When you do p = str(i), you are assigning to the variable p. And then your next line, p = getDF(i) overwrites the value of p. It does not write to a variable whose name is str(i) like you are expecting.
If you want to store values into named slots, you can use a dictionary:
p = {}
for i in list_db:
p[i] = getDF(i)

Python3 access previously created object

Im new to programming in general and I need some help for accessing a previously created instance of Class. I did some search on SO but I could not find anything... Maybe it's just because I should not try to do that.
for s in servers:
c = rconprotocol.Rcon(s[0], s[2],s[1])
t = threading.Thread(target=c.connect)
t.start()
c.messengers(allmessages, 10)
Now, what can I do if I want to call a function on "c" ?
Thanks, Hugo
You're creating several different objects that you briefly name c as you go through the loop. If you want to be able to access more than the last of them, you'll need to save them somewhere that won't be overwritten. Probably the best approach is to use a list to hold the successive values, but depending on your specific needs another data structure might make sense too (for instance, using a dictionary you could look up each value by a specific key).
Here's a trivial adjustment to your current code that will save the c values in a list:
c_list = []
for s in servers:
c = rconprotocol.Rcon(s[0], s[2],s[1])
t = threading.Thread(target=c.connect)
t.start()
c.messengers(allmessages, 10)
c_list.append(c)
Later you can access any of the c values with c_list[index], or by iterating with for c in c_list.
A slightly more Pythonic version might use a list comprehension rather than append to create the list (this also shows what a loop over c_list later one might look like):
c_list = [rconprotocol.Rcon(s[0], s[2],s[1]) for s in servers]
for c in c_list:
t = threading.Thread(target=c.connect)
t.start()
c.messengers(allmessages, 10)

Resources