Python dictionary.keys() error


I am trying to use the .keys() and instead of getting a list of the keys like
always have in the past. However I get this.

b = { 'video':0, 'music':23 }
k = b.keys()
print( k[0] )

>>>TypeError: 'dict_keys' object does not support indexing

print( k )
dict_keys(['music', 'video'])

it should just print [‘music’, ‘video’] unless I’m going crazy.

What’s going on?

Asked By: tokageKitayama



Python 3 changed the behavior of dict.keys such that it now returns a dict_keys object, which is iterable but not indexable (it’s like the old dict.iterkeys, which is gone now). You can get the Python 2 result back with an explicit call to list:

>>> b = { 'video':0, 'music':23 }
>>> k = list(b.keys())
>>> k
['music', 'video']

or just

>>> list(b)
['music', 'video']
Answered By: Fred Foo

If you assigned k like so:

k = list(b.keys())

your code will work.

As the error says, the dict_keys type does not support indexing.

Answered By: NPE

This is one of the breaking changes between Python 2 and 3.

In Python 2:

>>> help(dict.keys)
    D.keys() -> list of D's keys

In Python 3:

>>> help(dict.keys)
    D.keys() -> a set-like object providing a view on D's keys

This change in behavior makes a lot of sense since a dict is semantically unordered and its keys are unique – just like a set.

This change means that you don’t have to create a new list of keys every time you want to do some kind of set comparison with a dict’s keys.

Getting the same behavior in 2 and 3

To help transition to Python 3, Python 2.7 has another dict method, viewkeys. The viewkeys method is most similar to Python 3’s dict.keys method:

>>> d
{'a': None, 'c': None, 'b': None, 'd': None}
>>> for k in d.viewkeys(): print k
>>> d.viewkeys() & set('abc')
set(['a', 'c', 'b'])

In Python 3, the closest analog to the old behavior is to pass dict.keys() to list:

>>> d
{'d': None, 'a': None, 'c': None, 'b': None}
>>> list(d.keys())
['d', 'a', 'c', 'b']

Or just pass the dict to list, since a dict will iterate over its keys anyways:

>>> list(d)
['d', 'a', 'c', 'b']

You could create a utility functions to abstract the behavior over 2 and 3:

if hasattr(dict, 'viewkeys'): # Python 2.7
    def keys(d):
        return d.viewkeys()
else:  # Python 3
    def keys(d):
        return d.keys()

And pass a dict to list to get the list form, and in both 2 and 3, you’ll get the same output:

>>> d
{'b': None, 'a': None, 'c': None, 'd': None}
>>> keys(d)
dict_keys(['b', 'a', 'c', 'd'])
>>> list(d)
['b', 'a', 'c', 'd']

If you simply want a list of keys from a dictionary you can directly do like this:

b = {"name": "xyz", "class":"abc", "college": "qwert"}  
key_list = list(b)

key_list will contain all the key names as a list, though, this will not repeats a key, if found more than once. Duplicate keys will be counted as one.

Answered By: vikas0713
import random
b = { 'video':0, 'music':23,"picture":12 }

# Returns a random dictionary entry as a tuple:
# ('music', 23)
Answered By: ziya efkar