Using Dictionary get method to return empty list by default returns None instead

19,933

Solution 1

It's not dict.get( i, [] ) that's returning None, it's append. You probably want to use dict.setdefault(i, []).append(j) or just use a defaultdict in the first place.

Here's how you would do it:

d = {}
for i in range( 0, 10 ):
    for j in range( 0, 100 ):
        d.setdefault( i, [] ).append( j )

Note that I changed dict to d because dict already means something in Python (you're redefining it) and I removed the superfluous dict[i] = that was causing the error message.

Solution 2

To solve this you should use Python's defaultdict. The first time you use a key that doesn't exist, the argument to the defaultdict constructor is used to create a value (in this case, a list).

http://docs.python.org/library/collections.html#defaultdict-examples

from collections import defaultdict 

d = defaultdict(list)
for i in range( 0, 10 ):
    for j in range( 0, 100 ):
        d[i].append( j )

You can also pass a function as the argument to defaultdict if you want to do anything more elaborate.

Solution 3

The problem is that append returns None instead of the list object. So

dict[i] = dict.get( i, [] ).append( j ) assigns None to dict[i]

However, you can do much simpler:

dict.setdefault( i, [] ).append( j )

.. quoting the docs for setdefault:

If key is in the dictionary, return its value. If not, insert key with a value of default and return default

So if the key i is not yet present it creates it and stores the default value in it, in either case it returns the key value - which is a reference to the list, so you can modify it directly.

Solution 4

append doesn't return a list. It appends the value to the list and returns None.

Instead of this:

 dict[i] = dict.get( i, [] ).append( j ) 

You could do this:

 dict.setdefault(i, [])
 dict[i].append( j )

Solution 5

An alternative that uses the get method by taking advantage of list addition.

d = {}
for i in range(0, 10):
    for j in range(0, 100):
        d[i] = d.get(i, []) + [j]
Share:
19,933

Related videos on Youtube

Danielb
Author by

Danielb

Scottish computer games programmer.

Updated on May 30, 2022

Comments

  • Danielb
    Danielb almost 2 years

    In Python I would like to build up an dictionary of arrays using the dictionary get method to by default supply an empty list to then populate with information e.g.:

    dct = {}
    for i in range(0, 10):
        for j in range(0, 100):
            dct[i] = dct.get(i, []).append(j)
    

    However when I try the above code I get no exceptions but my list ends up like the following:

    AttributeError: 'NoneType' object has no attribute 'append'

    Lists have an append method, so I simplified my test to the following:

    dct = {}
    for i in range(0, 10):
        dct[i] = dct.get(i, []).append(i)
    

    And the output was the following:

    {0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}

    So my question is why is dct.get(i, []) returning None by default and not []? Doing dct.get(i, list()) has the same problem, so I am a bit stumped.

    • Nicholas Knight
      Nicholas Knight about 13 years
      Please please please do not use dict as a variable name. It clashes with the built-in dict class.
    • Danielb
      Danielb
      I don't typically do that, I just wanted to be clear as to what the variable was.
    • Steve Mayne
      Steve Mayne
      Your first setdefault code is flawed, don't assign back to dict[i]. dict.setdefault( i, [] ).append( j ) should be all you need.
    • Gabe
      Gabe
      You don't want the dict[i] = in front of the setdefault. See my edited answer.
    • Danielb
      Danielb
      Your correct, I just figured that out. May thanks, I wish I could make you all as correct :(
  • Danielb
    Danielb about 13 years
    Doing the append and setdefault on the same line caused an exception for me on Python 2.7.1.
  • Steve Mayne
    Steve Mayne about 13 years
    or, on one line: dict.setdefault(i, []).append( j ) - although it should be noted that defaultdict is faster.
  • Alexander Gessler
    Alexander Gessler about 13 years
    Works for me with both 2.6 and 3.1
  • jwg
    jwg almost 9 years
    This is the right answer. There are no bonus points in Python for 'rolling your own'.
  • martineau
    martineau almost 9 years
    Problem is this requires first making a one element list out of j in order to take advantage of it.