dict.keys()[0] on Python 3

Question:

I have this sentence:

def Ciudad(prob):
    numero = random.random()
    ciudad = prob.keys()[0]
    for i in prob.keys():
        if(numero > prob[i]):
            if(prob[i] > prob[ciudad]):
                ciudad = i
        else:
            if(prob[i] > prob[ciudad]):
                ciudad = i

    return ciudad

But when I call it this error pops:

TypeError: 'dict_keys' object does not support indexing

is it a version problem? I’m using Python 3.3.2

Asked By: Menticolcito

||

Answers:

In Python 3.x, dict.keys() does not return a list, it returns an iterable (specifically, a dictionary view). It is worth noting that dict itself is also an iterable of the keys.

If you want to obtain the first key, use next(iter(dict)) instead. (Note that before Python 3.6 dictionaries were unordered, so the ‘first’ element was an arbitrary one. Since 3.6 it will be based on insertion order. If you need that behaviour in older versions or with cross-version compatibility, you can use collections.OrderedDict).

This works quite simply: we take the iterable from the dictionary view with iter(), then use next() to advance it by one and get the first key.

If you need to iterate over the keys—then there is definitely no need to construct a list:

for key in dict:
    ...

These are all advantageous when compared to using list() as it means a list isn’t constructed – making it faster and more memory efficient (hence why the default behaviour of keys() was changed in 3.x). Even in Python 2.x you would be better off doing next(iter(dict.iterkeys()).

Note all these things apply to dict.values() and dict.items() as well.

Answered By: Gareth Latty

dict.keys() is a dictionary view. Just use list() directly on the dictionary instead if you need a list of keys, item 0 will be the first key in the (arbitrary) dictionary order:

list(prob)[0]

or better still just use:

next(iter(dict))

Either method works in both Python 2 and 3 and the next() option is certainly more efficient for Python 2 than using dict.keys(). Note however that dictionaries have no set order and you will not know what key will be listed first.

It looks as if you are trying to find the maximum key instead, use max() with dict.get:

def Ciudad(prob):
    return max(prob, key=prob.get)

The function result is certainly going to be the same for any given prob dictionary, as your code doesn’t differ in codepaths between the random number comparison branches of the if statement.

Answered By: Martijn Pieters

I’ve had success turning the iterables taken from a dictionary into a list.
So, for dic.keys(), dic.values(), and dic.items(), in Python3.6, you can:

dic = {'a':3, 'b':2, 'c':3}
print(dic)

dictkeys = dic.keys() # or values/items
print(dictkeys)

keylist = []
keylist.extend(iter(dictkeys)) # my big revelation
print('keylist', keylist)
Answered By: Tim Pozza