Python dictionary keys besides strings and integers?

Question:

Anyone have some neat examples of dictionaries with some interesting keys (besides the canonical string or integer), and how you used these in your program?

I understand all we need for a key is something hashable, meaning it must be immutable and comparable (has an __eq__() or __cmp__() method).

A related question is: how can I quickly and slickly define a new hashable?

Asked By: Pete

||

Answers:

You can use a tuple as a key, for example if you want to create a multi-column index. Here’s a simple example:

>>> index = {("John", "Smith", "1972/01/01"): 123, ("Bob", "Smith", "1972/01/02"): 124}
>>> index
{('Bob', 'Smith', '1972/01/02'): 124, ('John', 'Smith', '1972/01/01'): 123}
>>> index.keys()
[('Bob', 'Smith', '1972/01/02'), ('John', 'Smith', '1972/01/01')]
>>> index['John', 'Smith', '1972/01/01']
123

For an example of how to use a dict as a key (a hashable dict) see this answer:
Python hashable dicts

Answered By: patrickmdnet

Note that I’ve never really used this, but I’ve always thought using tuples as keys could let you do some interesting things. I would find it a convenient way to map grid coordinates, for example. You can think of this like a grid on a video game (maybe some kind of tactics game like Fire Emblem):

>>> Terrain = { (1,3):"Forest", (1,5):"Water", (3,4):"Land" }
>>> print Terrain
{(1, 5): 'Water', (1, 3): 'Forest', (3, 4): 'Land'}
>>> print Terrain[(1,3)]
Forest
>>> print Terrain[(1,5)]
Water
>>> x = 3
>>> y = 4
>>> print Terrain[(x,y)]
Land

Something like that.

Edit: As Mark Rushakof pointed out in the comments, I’m basically intending this to be a sparse array.

Answered By: eldarerathis

You left out the probably most important method for an object to be hashable: __hash__().

The shortest implementation of your own hashable type is this:

class A(object):
    pass

Now you can use instances of A as dictionary keys:

d = {}
a = A()
b = A()
d[a] = 7
d[b] = 8

This is because user-defined classes are hashable by default, and their hash value is their id — so they will only compare equal if they are the same object.

Note that instances of A are by no means immutable, and they can be used as dictionary keys nevertheless. The statement that dictionary keys must be immutable only holds for the built-in types.

Answered By: Sven Marnach

Let’s go for something a bit more esoteric. Suppose you wanted to execute a list of functions and store the result of each. For each function that raised an exception, you want to record the exception, and you also want to keep a count of how many times each kind of exception is raised. Functions and exceptions can be used as dict keys, so this is easy:

funclist = [foo, bar, baz, quux]

results    = {}
badfuncs   = {}
errorcount = {}

for f in funclist:
    try:
        results[f] = f()
    except Exception as e:
        badfuncs[f]   = e
        errorcount[type(e)] = errorcount[type(e)] + 1 if type(e) in errorcount else 1

Now you can do if foo in badfuncs to test whether that function raised an exception (or if foo in results to see if it ran properly), if ValueError in errorcount to see if any function raised ValueError, and so on.

Answered By: kindall

I have no idea why you’d want to do it (and preferably, please don’t do it)… but alongside strings and integers, you can also use both simultaneously. That is, as a beginner, I found it both powerful and surprising that:

foo = { 1:'this', 2:'that', 'more':'other', 'less':'etc' }

is an entirely valid dictionary, which provides access to foo[2] as easily as it does to foo['more'].

Answered By: omatai
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.