I was attempting to add an attribute to a pre-existing object in a dictionary:
key = 'key1'
dictObj = {}
dictObj[key] = "hello world!"
#attempt 236 (j/k)
dictObj[key]["property2"] = "value2" ###'str' object does not support item assignment
#another attempt
setattr(dictObj[key], 'property2', 'value2') ###'dict' object has no attribute 'property2'
#successful attempt that I did not like
dictObj[key] = {'property':'value', 'property2':''} ###instantiating the dict object with all properties defined seemed wrong...
#this did allow for the following to work
dictObj[key]["property2"] = "value2"
I tried various combinations (including setattr, etc.) and was not having much luck.
Once I have added an item to a Dictionary, how can I add additional key/value pairs to that item (not add another item to the dictionary).
As I was writing up this question, I realized my mistake.
key = 'key1'
dictObj = {}
dictObj[key] = {} #here is where the mistake was
dictObj[key]["property2"] = "value2"
The problem appears to be that I was instantiating the object with key 'key1' as a string instead of a dictionary. As such, I was not able to add a key to a string. This was one of many issues I encountered while trying to figure out this simple problem. I encountered KeyErrors as well when I varied the code a bit.
Strictly reading the question, we are considering adding an attribute to the object. This can look like this:
class DictObj(dict):
pass
dictObj = DictObj(dict)
dictObj.key = {'property2': 'value2'}
And then, we can use dictObj.key == {'property2': 'value2'}
Given the context of the question, we are dealing with adding a property to the dictionary. This can be done (in addition to #John Bartels's approach) in the following ways:
1st option - add the "full" content in one line:
dictObj = {'key': {'property2': 'value2'}}
2nd option for the case of dictionary creation with initial values:
dictObj = dict(key = dict(property2 = 'value2'))
3rd option (Python 3.5 and higher):
dictObj = {}
dictObj2 = {'key': {'property2': 'value2'}}
dictObj = {**dictObj, **dictObj2}
4th option (Python 3.9 and higher):
dictObj = {}
dictObj |= {'key': {'property2': 'value2'}}
In all cases the result will be: dictObj == {'key': {'property2': 'value2'}}
Related
If I have a dictionary that is nested, and I pass in a string like "key1.key2.key3" which would translate to:
myDict["key1"]["key2"]["key3"]
What would be an elegant way to be able to have a method where I could pass on that string and it would translate to that key assignment? Something like
myDict.set_nested('key1.key2.key3', someValue)
Using only builtin stuff:
def set(my_dict, key_string, value):
"""Given `foo`, 'key1.key2.key3', 'something', set foo['key1']['key2']['key3'] = 'something'"""
# Start off pointing at the original dictionary that was passed in.
here = my_dict
# Turn the string of key names into a list of strings.
keys = key_string.split(".")
# For every key *before* the last one, we concentrate on navigating through the dictionary.
for key in keys[:-1]:
# Try to find here[key]. If it doesn't exist, create it with an empty dictionary. Then,
# update our `here` pointer to refer to the thing we just found (or created).
here = here.setdefault(key, {})
# Finally, set the final key to the given value
here[keys[-1]] = value
myDict = {}
set(myDict, "key1.key2.key3", "some_value")
assert myDict == {"key1": {"key2": {"key3": "some_value"}}}
This traverses myDict one key at a time, ensuring that each sub-key refers to a nested dictionary.
You could also solve this recursively, but then you risk RecursionError exceptions without any real benefit.
There are a number of existing modules that will already do this, or something very much like it. For example, the jmespath module will resolve jmespath expressions, so given:
>>> mydict={'key1': {'key2': {'key3': 'value'}}}
You can run:
>>> import jmespath
>>> jmespath.search('key1.key2.key3', mydict)
'value'
The jsonpointer module does something similar, although it likes / for a separator instead of ..
Given the number of pre-existing modules I would avoid trying to write your own code to do this.
EDIT: OP's clarification makes it clear that this answer isn't what he's looking for. I'm leaving it up here for people who find it by title.
I implemented a class that did this a while back... it should serve your purposes.
I achieved this by overriding the default getattr/setattr functions for an object.
Check it out! AndroxxTraxxon/cfgutils
This lets you do some code like the following...
from cfgutils import obj
a = obj({
"b": 123,
"c": "apple",
"d": {
"e": "nested dictionary value"
}
})
print(a.d.e)
>>> nested dictionary value
I have the following dictionary (It is for creating json),
temp = {'logs':[]}
I want to append dictionaries, but i only got 1 key:val at a time.
what I tried:
temp['logs'].append({key:val})
This does as expected and appends the dict to the array.
But now I want to add a key/val pair to this dictionary, how can I do this?
I've tried using append/extend but that just adds a new dictionary to the list.
But now I want to add a key/val pair to this dictionary
You can index the list and update that dictionary:
temp['logs'][0].update({'new_key': 'new_value'})
You can use this command to change your dict values :
>>> temp['logs'][0]={'no':'val'}
>>> temp
{'logs': [{'no': 'val'}]}
And this one to add values :
>>> temp['logs'][0].update({'yes':'val'})
>>> temp
{'logs': [{'key': 'val', 'yes': 'val'}]}
There must be unique "key" every time you append it. (If it is for json)
Also making "=" will update your old dictionary
What I have done when I was stuck once is
user = {}
name,password,id1 = [],[],[]
user1=session.query(User).all()
for i in user1:
name=i.name
password=i.password
id1=i.id
user.update({ id1:{
"name" : name,
"password" : password,
}
})
check this link might be helpful to you
How to convert List of JSON frames to JSON frame
Note that adding a dictionary (or any object) to a list only stores a reference, not a copy.
You can therefor do this:
>>> temp = {'logs': []}
>>> log_entry = {'key1': 'val1'}
>>> temp['logs'].append(log_entry)
>>> temp
{'logs': [{'key1': 'val1'}]}
>>> log_entry['key2'] = 'val2'
>>> temp
{'logs': [{'key2': 'val2', 'key1': 'val1'}]}
However, you might be able to circumvent to whole issue by using dict comprehension (only in Python >=2.7)
>>> temp = {'logs': [{key: value for key, value in my_generator}]
Try this example:
temp = {
'logs':[]
}
[temp['logs'].append(log) for log in errors['logs']]
Your log data would be list with multiple dictionary
So i have following dict:
my_dict{'key1': 'value1',
'key2': 'value2',
'key3': json.dumps([
{"**subkey1**": "subvalue1", "**subkey2**": "subvalue2",},
{"**subkey1**": "other_subvalue", "**subkey2**":"other_subvalue2"}])
}
What I need is to somehow made a def where i have to check and for each subkey2 to change its value only for the def itself
And all subkey1 to check if its value is the same like the second subkey1
Please note I am talking about only subkey1 which I have twice.
I don't want to set them manually. Mean I have this dict global, and calling it from many def, so i need to make these changes and check inside each def
What I tried is:
def recurse_keys(my_dict, indent = ''):
print(indent+str(key))
if isinstance(my_dict[key], dict):
recurse_keys(my_dict[key], indent+' ')
recurse_keys(my_dict)
And for now it is only printing all of my params, but am not sure how to proceed
Example:
my_dict{'name': 'georgi',
'famili': 'ivanov',
'drinks': json.dumps([
{"breakfast": "milk", "lunch": "beer",},
{"breakfast": "tea", "lunch":"vodka"}])
def test()
....check if both breakfast are the same and if not make them so....(all these, mean dict and the function it self are in same file)
so I need to check if the values for the two breakfast are the same (without to know them) and if they are not, to make them so.
And also to check if there is lunch with empty value or 0 and again if not, to make it so
If you want to edit a json string, then probably the easiest way is to decode it to python data types d = json.loads(str), edit it, then encode it back to string str = json.dumps(d) (python JSON).
import json
my_dict = {'name': 'georgi',\
'famili': 'ivanov',\
'drinks': json.dumps([\
{"breakfast": "milk", "lunch": "beer",},\
{"breakfast": "tea", "lunch":"vodka"}])};
ddict = json.loads(my_dict["drinks"]) # json str to python data types
seen = {}; # store the items already seen
# for each dictionary object in key3
for d in range(0,len(ddict)):
for k in ddict[d]:
if k in seen:
# update the value to the one already seen
ddict[d][k] = seen[k];
if k == "lunch" and (ddict[d] == "" or ddict[d] is None):
ddict[d] = alternative_lunch_value;
else:
seen[k] = ddict[d][k];
my_dict["drinks"] = json.dumps(ddict);
print(my_dict);
The result on my machine is:
{'drinks': '[{"breakfast": "milk", "lunch": "beer"}, {"breakfast": "milk", "lunch": "beer"}]',
'famili': 'ivanov',
'name': 'georgi'}
Updating dict values
Because you wanted to update the values in my_dict so that it can be read by other modules, rather than just read the values. If all you wanted to do was read the values, then you can iterate over the list ddict as follows:
for value in ddict:
print("Sub1:{0} Sub2:{1}\n".format(value["**subkey1**"], value["**subkey2**"]));
However, since you want to update the values in the existing list, then you will need to iterate over a list of the indexes. As shown below...
Range() and len()
Range(start,end) gives a list with values from start to end. So a = range(1,4) assigns [1,2,3,4] to a. Also len(a) will return the number of items in the list, so 4 in this case. Using these principals, you can iterate through your ddict.
for d in range(1,len(ddict):
ddict[d]["**subkey1**"] = new_value;
Hope this helps get you started. If you update your question with more details on exactly what you want (i.e. example input and output, perhaps psudo code), then we will be able to give you a better answer.
[Python 3.4.2]
I know this question sounds ridiculous, but I can't figure out where I'm messing up. I'm trying to add keys and values to a dictionary by using strings instead of quoted text. So instead of this,
dict['key'] = value
this:
dict[key] = value
When I run the command above, I get this error:
TypeError: 'str' object does not support item assignment
I think Python is thinking that I'm trying to create a string, not add to a dictionary. I'm guessing I'm using the wrong syntax. This is what I'm trying to do:
dict[string_for_key][string_for_value] = string_for_deeper_value
I want this^ command to do this:
dict = {string_for_key: string_for_value: string_for_deeper_value}
I'm getting this error:
TypeError: 'str' object does not support item assignment
I should probably give some more context. I'm:
creating one dictionary
creating a copy of it (because I need to edit the dictionary while iterating through it)
iterating through the first dictionary while running some queries
trying to assign a query's result as a value for each "key: value" in the dictionary.
Here's a picture to show what I mean:
key: value: query_as_new_value
-----EDIT-----
Sorry, I should have clarified: the dictionary's name is not actually 'dict'; I called it 'dict' in my question to show that it was a dictionary.
-----EDIT-----
I'll just post the whole process I'm writing in my script. The error occurs during the last command of the function. Commented out at the very bottom are some other things I've tried.
from collections import defaultdict
global query_line, pericope_p, pericope_f, pericope_e, pericope_g
def _pre_query(self, typ):
with open(self) as f:
i = 1
for line in f:
if i == query_line:
break
i += 1
target = repr(line.strip())
###skipping some code
pericope_dict_post[self][typ] = line.strip()
#^Outputs error TypeError: 'str' object does not support item assignment
return
pericope_dict_pre = {'pericope-p.txt': 'pericope_p',
'pericope-f.txt': 'pericope_f',
'pericope-e.txt': 'pericope_e',
'pericope-g.txt': 'pericope_g'}
pericope_dict_post = defaultdict(dict)
#pericope_dict_post = defaultdict(list)
#pericope_dict_post = {}
for key, value in pericope_dict_pre.items():
pericope_dict_post[key] = value
#^Works
#pericope_dict_post.update({key: value})
#^Also works
#pericope_dict_post.append(key)
#^AttributeError: 'dict' object has no attribute 'append'
#pericope_dict_post[key].append(value)
#^AttributeError: 'dict' object has no attribute 'append'
_pre_query(key, value)
-----FINAL EDIT-----
Matthias helped me figure it out, although acushner had the solution too. I was trying to make the dictionary three "levels" deep, but Python dictionaries cannot work this way. Instead, I needed to create a nested dictionary. To use an illustration, I was trying to do {key: value: value} when I needed to do {key: {key: value}}.
To apply this to my code, I need to create the [second] dictionary with all three strings at once. So instead of this:
my_dict[key] = value1
my_dict[key][value1] = value2
I need to do this:
my_dict[key][value1] = value2
Thanks a ton for all your help guys!
You could create a dictionary that expands by itself (Python 3 required).
class AutoTree(dict):
"""Dictionary with unlimited levels"""
def __missing__(self, key):
value = self[key] = type(self)()
return value
Use it like this.
data = AutoTree()
data['a']['b'] = 'foo'
print(data)
Result
{'a': {'b': 'foo'}}
Now I'm going to explain your problem with the message TypeError: 'str' object does not support item assignment.
This code will work
from collections import defaultdict
data = defaultdict(dict)
data['a']['b'] = 'c'
data['a'] doesn't exist, so the default value dict is used. Now data['a'] is a dict and this dictionary gets a new value with the key 'b' and the value 'c'.
This code won't work
from collections import defaultdict
data = defaultdict(dict)
data['a'] = 'c'
data['a']['b'] = 'c'
The value of data['a'] is defined as the string 'c'. Now you can only perform string operations with data['a']. You can't use it as a dictionary now and that's why data['a']['b'] = 'c' fails.
first, do not use dict as your variable name as it shadows the built-in of the same name.
second, all you want is a nested dictionary, no?
from collections import defaultdict
d = defaultdict(dict)
d[string_for_key][string_for_value] = 'snth'
another way, as #Matthias suggested, is to create a bottomless dictionary:
dd = lambda: defaultdict(dd)
d = dd()
d[string_for_key][string_for_value] = 'snth'
you can do something like this:
>>> my_dict = {}
>>> key = 'a' # if key is not defined before it will raise NameError
>>> my_dict[key] = [1]
>>> my_dict[key].append(2)
>>> my_dict
{'a': [1, 2]}
Note: dict is inbuilt don't use it as variable name
I was wondering if there was a way to initialize a dictionary in python with keys but no corresponding values until I set them. Such as:
Definition = {'apple': , 'ball': }
and then later i can set them:
Definition[key] = something
I only want to initialize keys but I don't know the corresponding values until I have to set them later. Basically I know what keys I want to add the values as they are found. Thanks.
Use the fromkeys function to initialize a dictionary with any default value. In your case, you will initialize with None since you don't have a default value in mind.
empty_dict = dict.fromkeys(['apple','ball'])
this will initialize empty_dict as:
empty_dict = {'apple': None, 'ball': None}
As an alternative, if you wanted to initialize the dictionary with some default value other than None, you can do:
default_value = 'xyz'
nonempty_dict = dict.fromkeys(['apple','ball'],default_value)
You could initialize them to None.
you could use a defaultdict. It will let you set dictionary values without worrying if the key already exists. If you access a key that has not been initialized yet it will return a value you specify (in the below example it will return None)
from collections import defaultdict
your_dict = defaultdict(lambda : None)
It would be good to know what your purpose is, why you want to initialize the keys in the first place. I am not sure you need to do that at all.
1) If you want to count the number of occurrences of keys, you can just do:
Definition = {}
# ...
Definition[key] = Definition.get(key, 0) + 1
2) If you want to get None (or some other value) later for keys that you did not encounter, again you can just use the get() method:
Definition.get(key) # returns None if key not stored
Definition.get(key, default_other_than_none)
3) For all other purposes, you can just use a list of the expected keys, and check if the keys found later match those.
For example, if you only want to store values for those keys:
expected_keys = ['apple', 'banana']
# ...
if key_found in expected_keys:
Definition[key_found] = value
Or if you want to make sure all expected keys were found:
assert(all(key in Definition for key in expected_keys))
You can initialize the values as empty strings and fill them in later as they are found.
dictionary = {'one':'','two':''}
dictionary['one']=1
dictionary['two']=2
Comprehension could be also convenient in this case:
# from a list
keys = ["k1", "k2"]
d = {k:None for k in keys}
# or from another dict
d1 = {"k1" : 1, "k2" : 2}
d2 = {k:None for k in d1.keys()}
d2
# {'k1': None, 'k2': None}
q = input("Apple")
w = input("Ball")
Definition = {'apple': q, 'ball': w}
Based on the clarifying comment by #user2989027, I think a good solution is the following:
definition = ['apple', 'ball']
data = {'orange':1, 'pear':2, 'apple':3, 'ball':4}
my_data = {}
for k in definition:
try:
my_data[k]=data[k]
except KeyError:
pass
print my_data
I tried not to do anything fancy here. I setup my data and an empty dictionary. I then loop through a list of strings that represent potential keys in my data dictionary. I copy each value from data to my_data, but consider the case where data may not have the key that I want.