user2821275
user2821275

Reputation:

Python: Error retrieving and modifying values in a dictionary using .append()?

Let's say I have a list of characters and I want to map each to the number of times it occurs in the list. The following code accomplishes this:

characters = ['a','b','c','a']
d = {}
for ch in characters:
   d[ch] = d.get(ch,0) + 1
return d

Now let's say, instead of having each character mapped to the number of times it occurs in the list, I want to map it to a list of 1's, where each 1 represents an occurance in the list. So for example, something like {a:[1,1], b:[1], c:[1]}. I use the same format but it doesn't work. Can someone explain why not?

characters = ['a','b','c','a']
d = {}
for ch in characters:
   d[ch] = d.get(ch,[]).append(1)
#print type(d['a'])
return d

I get AttributeError: 'NoneType' object has no attribute 'append', even though a print type(d['a']) returns "list" if I remove the .append() in the for loop. Thanks!

Upvotes: 0

Views: 77

Answers (5)

vivek
vivek

Reputation: 2867

This is my proposed solutions:

characters = ['a','b','c','a']
d = {}
for ch in characters:
    d.setdefaultappend(ch, []).append(1)
return d

Upvotes: 0

Timothy
Timothy

Reputation: 155

use python dir function

list has append method

dist has no append method

>>> characters = []
>>> d = {}
>>> dir(characters)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', 
'__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', 
'__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', 
'__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append',
'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

>>> dir(d)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', 
'__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', 
'__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 
'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 
'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

Upvotes: -1

Nasir
Nasir

Reputation: 2122

The line d[ch] = d.get(ch,[]).append(1) sets d[ch] to the value returned by append function which is None. Do this instead:

d[ch] = d.get(ch, [])
d[ch].append(1)

Upvotes: 0

jamylak
jamylak

Reputation: 133574

characters = ['a','b','c','a']
d = {}
for ch in characters:
   d[ch] = d.get(ch,[]).append(1)
#print type(d['a'])
return d

dict.get returns the value at the key ch and if it doesn't exist it returns the default value you provided, the list [] you have created. Anyway, I think you may be confused because d.get doesn't set any values, it only returns one. Then you are appending 1 to this list. .append is an inplace operation so it won't return the post-appended list as you may have expected, it simply returns None to signify that it is not supposed to be used the way you have. What you could do instead is

d.setdefault(ch, []).append(1)

Which does what you would expect ;) To avoid this crazy syntax you could make use of a collections.defaultdict like so:

d = defaultdict(list)
d[ch].append(1)

which looks much cleaner

Upvotes: 2

cwallenpoole
cwallenpoole

Reputation: 82028

You're assigning the value of d[ch] to the return value of [].append. Think of it this way your code is the equivalent of

tmp = d.get(ch,[])
d[ch] = tmp.append(1)

Try this instead:

d[ch] = d.get(ch,[])
d[ch].append(1)

Upvotes: 0

Related Questions