Python : AttributeError: 'int' object has no attribute 'append' - python

I have a dict of int, list. What I'm trying to do is loop through `something' and if the key is present in the dict add the item to the lsit or else create a new list and add the item.
This is my code.
levels = {}
if curr_node.dist in levels:
l = levels[curr_node.dist]
l.append(curr_node.tree_node.val)...........***
else:
levels[curr_node.dist] = []
levels[curr_node.dist].append(curr_node.tree_node.val)
levels[curr_node.dist] = curr_node.tree_node.val
My question is two-fold.
1. I get the following error,
Line 27: AttributeError: 'int' object has no attribute 'append'
Line 27 is the line marked with ***
What am I missing that's leading to the error.
How can I run this algorithm of checking key and adding to a list in a dict more pythonically.

You set a list first, then replace that list with the value:
else:
levels[curr_node.dist] = []
levels[curr_node.dist].append(curr_node.tree_node.val)
levels[curr_node.dist] = curr_node.tree_node.val
Drop that last line, it breaks your code.
Instead of using if...else, you could use the dict.setdefault() method to assign an empty list when the key is missing, and at the same time return the value for the key:
levels.setdefault(curr_node.dist, []).append(curr_node.tree_node.val)
This one line replaces your 6 if: ... else ... lines.
You could also use a collections.defaultdict() object:
from collections import defaultdict
levels = defaultdict(list)
and
levels[curr_node.dist].append(curr_node.tree_node.val)
For missing keys a list object is automatically added. This has a downside: later code with a bug in it that accidentally uses a non-existing key will get you an empty list, making matters confusing when debugging that error.

Related

Append object to sub json key PYTHON

I am trying to append an object in a loop to one of two sub keys created in a json object.
for agency in q:
dashboard[agency.id]= []
dashboard[agency.id].append({"name": agency.agency.name})
dashboard[agency.id].append({"stats": []})
dashboard[agency.id].append({"users": []})
for row in stats:
if row['is_agency']:
dashboard[row['agency_id']['stats']].append(dict(row))
else:
dashboard[row['agency_id']['users']].append(dict(row))
But it is throwing an error of:
dashboard[row['agency_id']]['users'].append(dict(row))
TypeError: list indices must be integers, not str
If I remove ['users'] or ['stats'] key it appends to the agency.id key just fine. But when I try to add it as a second level key, it throws the above error.
As the json object will always have the 3 sub keys (name[0], stats[1], users[2]) I have also then tried using:
for row in stats:
if row['is_agency']:
dashboard[row['agency_id']][1].append(dict(row))
else:
dashboard[row['agency_id']][2].append(dict(row))
That results in an error of the following:
dashboard[row['agency_id']][2].append(dict(row))
AttributeError: 'dict' object has no attribute 'append'
You are confusing the types and methods of your objects, as user #Moses Koledoye shows, if you do:
dashboard[row['agency_id']][1]['stats'].append(row)
Step by Step:
row['agency_id'] is an Int, so
dashboard[row['agency_id']] #has type list
will give you the value of the key row['agency_id'], of type List
dashboard[row['agency_id']][1]
gives to you the value in the position 1 of the list
`dashboard[row['agency_id']][1]['stats']` #is a List also
finally gives to you the list of stats (taking it as example), that's why you can use the append method:
dashboard[row['agency_id']][1]['stats'].append(row)

runtime error with python dictionary while using defaultdict

I am using a dictionary to add key and values in it. I am checking if the key is already present, and if yes, I am appending the value; if not I add a key and the corresponding value.
I am getting the error message:
AttributeError: 'str' object has no attribute 'append'
Here is the code. I am reading a CSV file:
metastore_dir = collections.defaultdict(list)
with open(local_registry_file_path + data_ext_dt + "_metastore_metadata.csv",'rb') as metastore_metadata:
for line in metastore_metadata:
key = line[2]
key = key.lower().strip()
if (key in metastore_dir):
metastore_dir[key].append(line[0])
else:
metastore_dir[key] = line[0]
I found the answer on stack overflow which says to use defaultdict to resolve the issue, i am getting the error message even after the suggested anwer.
I have pasted my code for reference.
The str type has no append() method.
Replace your call to append with the + operator:
sentry_dir[key] += line[1]
It is a dictionary of strings. To declare it as a list use
if (key not in metastore_dir): ## add key first if not in dict
metastore_dir[key] = [] ## empty list
metastore_dir[key].append(line[0])
""" with defaultdict you don't have to add the key
i.e. "if key in" not necessary
"""
metastore_dir[key].append(line[0])
When you insert a new item into the dictionary, you want to insert it as a list:
...
if (key in metastore_dir):
metastore_dir[key].append(line[0])
else:
metastore_dir[key] = [line[0]] # wrapping it in brackets creates a singleton list
On an unrelated note, it looks like you are not correctly parsing the CSV. Trying splitting each line by commas (e.g. line.split(',')[2] refers to the third column of a CSV file). Otherwise line[0] refers to the first character of the line and line[2] refers to the third character of the line, which I suspect is not what you want.

Python - Add to a dictionary using a string

[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

Error with Python dictionary: str object has no attribute append

I am writing code in python.
My input line is "all/DT remaining/VBG all/NNS of/IN "
I want to create a dictionary with one key and multiple values
For example - all:[DT,NNS]
groupPairsByKey={}
Code:
for line in fileIn:
lineLength=len(line)
words=line[0:lineLength-1].split(' ')
for word in words:
wordPair=word.split('/')
if wordPair[0] in groupPairsByKey:
groupPairsByKey[wordPair[0]].append(wordPair[1])
<getting error here>
else:
groupPairsByKey[wordPair[0]] = [wordPair[1]]
Your problem is that groupPairsByKey[wordPair[0]] is not a list, but a string!
Before appending value to groupPairsByKey['all'], you need to make the value a list.
Your solution is already correct, it works perfectly in my case. Try to make sure that groupPairsByKey is a completely empty dictionary.
By the way, this is what i tried:
>>> words = "all/DT remaining/VBG all/NNS of/IN".split
>>> for word in words:
wordPair = word.split('/')
if wordPair[0] in groupPairsByKey:
groupPairsByKey[wordPair[0]].append(wordPair[1])
else:
groupPairsByKey[wordPair[0]] = [wordPair[1]]
>>> groupPairsByKey
{'of': ['IN'], 'remaining': ['VBG'], 'all': ['DT', 'NNS']}
>>>
Also, if your code is formatted like the one you posted here, you'll get an indentationError.
Hope this helps!
Although it looks to me like you should be getting an IndentationError, if you are getting the message
str object has no attribute append
then it means
groupPairsByKey[wordPair[0]]
is a str, and strs do not have an append method.
The code you posted does not show how
groupPairsByKey[wordPair[0]]
could have a str value. Perhaps put
if wordPair[0] in groupPairsByKey:
if isinstance(groupPairsByKey[wordPair[0]], basestring):
print('{}: {}'.format(*wordPair))
raise Hell
into your code to help track down the culprit.
You could also simplify your code by using a collections.defaultdict:
import collections
groupPairsByKey = collections.defaultdict(list)
for line in fileIn:
lineLength=len(line)
words=line[0:lineLength-1].split(' ')
for word in words:
wordPair=word.split('/')
groupPairsByKey[wordPair[0]].append(wordPair[1])
When you access a defaultdict with a missing key, the factory function -- in this case list -- is called and the returned value is used as the associated value in the defaultdict. Thus, a new key-value pair is automatically inserted into the defaultdict whenever it encounters a missing key. Since the default value is always a list, you won't run into the error
str object has no attribute append anymore -- unless you have
code which reassigns an old key-value pair to have a new value which is a str.
You can do:
my_dict["all"] = my_string.split('/')
in Python,

Create a list of defaultdict in python

I am doing the following :
recordList=[lambda:defaultdict(str)]
record=defaultdict(str)
record['value']='value1'
record['value2']='value2'
recordList.append(record)
for record in recordList:
params = (record['value'],record['value2'],'31')
i am getting the error :
TypeError: 'function' object is not
subscriptable
what is wrong here ?
recordList=[lambda:defaultdict(str)]
creates a list with a function that returns defaultdict(str). So it's basically equivalent to:
def xy ():
return defaultdict(str)
recordList = []
recordList.append( xy )
As such, when you start your for loop, you get the first element from the list, which is not a list (as all the other elements you push to it), but a function. And a function does not have a index access methods (the ['value'] things).
recordList is a list with 1 element which is a function.
If you replace the first line with
recordList = []
the rest will wor.
you're adding a lambda to recordList, which is of type 'function'. in the for .. loop, you're trying to subscript it (record['value'], record['value2'], etc)
Initialize recordList to an empty list ([]) and it will work.

Categories