Dictionaries, Hovercraft, Eels


Tobacconist     What?
Hungarian     (miming matches) My hovercraft is full of eels.
Tobacconist     Matches, matches? (showing some)

Dictionaries, Hovercraft, Eels

Welcome to the new look site (which, due the wonder of CSS, has been retrospectively applied to all the earlier tutes)!  This was chosen because it was the first template I found which allowed you to see the whole of the code snippets.

In our earlier tutes we needed to come up with a way to keep track of questions in our trivia game.  We chose to use a list to do that (because that was the only data structure we knew of), but there was another option open to us – a dictionary:

>>> aDictionary = {}
>>> aDictionary
{}

What this code does is create a dictionary which is empty.  We can use the introspection trick we learned in the second last tute to find out a little about our dictionary:

>>> print aDictionary.__doc__
dict() -> new empty dictionary.
dict(mapping) -> new dictionary initialized from a mapping object's
(key, value) pairs.
dict(seq) -> new dictionary initialized as if via:
d = {}
for k, v in seq:
d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list.  For example:  dict(one=1, two=2)

Homework: try dir(aDictionary)

So, a “dictionary” has “(key, value) pairs” apparently.  What are these things?  You can think of dictionaries as a generalisation of lists.  In our earlier examples we got the contents of the lists by a number.  The number 0 was used to store the question in the trivia list (if you’ve forgotten it was in this tute).  In that case the number 0 was the “key”, and the text of the question was the “value”. A list only allows you to use numbers as keys. However, dictionaries don’t limit you in that way.  This means that you can give meaningful names to your keys. Let’s add something to our dictionary:

>>> aDictionary["I would like to buy some matches"] = "My hovercraft is full of eels"
>>> aDictionary
{'I would like to buy some matches': 'My hovercraft is full of eels'}

Here the “key” is the string ‘I would like to buy some matches’.  The value is also a string‘My hovercraft is full of eels’. The print out indicates that the object aDictionary is a dictionary by enclosing the output in curly braces -> {}.  Note also that we use the key to reference a value in the dictionary by using square brackets [] in much the same way as we used square brackets to identify members of the list in earlier tutes.

The key ‘I would like to buy some matches’ is a somewhat unusual key. How about we add another (key, value) pair:

>>> aDictionary['it'] = 'The word the Knights of Ni! cannot stand'
>>> aDictionary['Monty Python'] = "A famous comedy troupe from Britain, most active in the 70s and early 80s and on whom the name of the programming language Python is based."
>>> aDictionary
{'I would like to buy some matches': 'My hovercraft is full of eels', 'Monty Python': 'A famous comedy troupe from Britain, most active in the 70s and early 80s and on whom the name of the programming language Python is based.', 'it': 'The word the Knights of Ni! cannot stand'}

Here, aDictionary is acting how you would normally expect a dictionary (no italics, here I mean the sort of dictionary you’d find on a bookshelf) to operate – give it a word (‘it’), and it gives you a meaning for the word.  You should also note here that there is no necessary ordering of a dictionary*1 – in this case ‘it’ comes after ‘Monty Python’ in the print out even though alphabetically ‘it’ should come first.

Dictionaries allow us to set up a direct relationship between the key and the value. In theory, dictionaries give you a speed advantage for looking up values, especially for a large number of keys (this is a result of how dictionaries are implemented).  The reason I use dictionaries is that they usually give me a better way to remember what I am talking about.  So for example, we used sampleQuestion[1] to refer to the correct answer in our list. However, why should ‘1’ identify the correct answer?  If it was a dictionary, rather than a list, we could, instead, have written sampleQuestion[‘correctAnswer’].  This takes more typing, but in the long run is better because it is clearer what is going on with the code.

That said, lists can be massaged to address this readability issue.  One defines constants with a meaningful name, and then refers to elements by the constants:

CORRECT_ANSWER = 1
sampleQuestion[CORRECT_ANSWER]  # (Same as sampleQuestion[1])

By convention, if a variable is to be used as a constant (ie with a value which does not change) it is given a name consisting of all UPPERCASE LETTERS, as we have done here.  If all the letters are uppercase, there’s no ability for a change in case to indicate a separate word in the name, so we use underscores _ to add meaning.

However, dictionaries still provide some other advantages.  If you ever needed to change your data structure, you would be affected by the ordering of the list. In the data structure we’ve adopted for our trivia game, you could not, for example, include an alternative correct answer because there is literally nowhere to put it in the list*2 – the first entry is the question, the second entry is the right answer and the third and subsequent entries are wrong answers.  You can’t put it at the end, because that’s where wrong answers go and there’s nowhere else left up front.  However, if sampleQuestion was a dictionary, you just add another (key,value) pair (the key might be “alternativeCorrectAnswer”).  Importantly this would not break any existing code which processed a dictionary with existing data.<- in bold because it’s important!  Existing code would look for one of the existing keys, but would not be troubled by the existence of a new key.

That said, the main reason I use dictionaries is not explicitly for this flexibility or for the potential speed advantage.  Rather, I find the concept easy to understand in the first place, and I also find it more easy to understand code which I have written previously if I’ve used a dictionary.

You can get a list of keys in a dictionary (and a list of values):

>>> aDictionary.keys()
['I would like to buy some matches', 'Monty Python', 'it']
>>> aDictionary.values()
['My hovercraft is full of eels', 'A famous comedy troupe from Britain, most active in the 70s and early 80s and on whom the name of the programming language Python is based.', 'The word the Knights of Ni! cannot stand']
>>>

More freaky however, is that you can iterate over all of the keys if you want to:

>>> for k in aDictionary.keys():
...     print "The key is ->",k,"\nand its associated value is ->",aDictionary[k]
...
The key is -> I would like to buy some matches
and its associated value is -> My hovercraft is full of eels
The key is -> Monty Python
and its associated value is -> A famous comedy troupe from Britain, most active in the 70s and early 80s and on whom the name of the programming language Python is based.
The key is -> it
and its associated value is -> The word the Knights of Ni! cannot stand

Is that cool?  In this code each key in aDictionary is assigned in turn to the variable k, so the value corresponding to that key can be accessed by aDictionary[k].

I think it’s way cool.

Homework: make a dictionary which has the name of your friends as keys, and the name of the friend’s favourite game as the value of the key.  Hint: the .__doc__ printout above shows a fast way to create a dictionary populated with keys eg: faveGames = dict(Arthur=”chess”,Hildegard=”Cortex Command”)

PS:

Here’s a site which translates “my hovercraft is full of eels” into various languages

Notes:
*1 Python has another object which will give you an ordered dictionary, but we don’t need it at the moment.

*2 You could, if you were desperate, but it would take a bit of effort, and/or not work with (ie ‘break’) your existing data.

3 Responses to Dictionaries, Hovercraft, Eels

  1. I prefer
    for k, v in adict.items()
    to
    for k in adict.keys():
    v= adict[k]

  2. techtonik says:

    Kids need pictures!

  3. Pingback: Links 13/4/2011: Linux 2.6.39 RC3, Fedora 16 is Verne | Techrights

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.