IHE Python coure, 2017

Dictionaries: the famous Python dict object

T.N.Olsthoorn, Feb26, 2007


In [68]:
from pprint import pprint # import pretty print function. Can be used instead of print function.

dict, (dictionary), Pythons workhorse to store data in away it can be lookup by key in an extremely fast way, because the keys are hashed (transformed in an integer that allows fast lookup). They are everywhere in the Python core and readily available for use by you.

Looking up a value in a dict mydict stored under a given key key

value = myDict[key]

adding a new value under a new key:

myDict[newKey] = newValue

A key can be anythign that is hashable, that is, a key must at leasat be immutable. Immutable objects are

  • numbers
  • strings
  • tuples with immutable contents
  • frozenset

A dict can be generated by specifying key : value pairs between braces:


In [69]:
pets1 = {'cat' : ['spooky', 'fat tail'],
         'dog' : ['barky', 'Donald', 'Fikky'],
         'horse' : ['duke','bishop', 'knight']}

In [71]:
pets1['cat']


Out[71]:
['spooky', 'fat tail']

In [73]:
pprint(pets1)


{'cat': ['spooky', 'fat tail'],
 'dog': ['barky', 'Donald', 'Fikky'],
 'horse': ['duke', 'bishop', 'knight']}

In [45]:
print(pets1)
print()
pprint(pets1)


{'cat': ['spooky', 'fat tail'], 'horse': ['duke', 'bishop', 'knight'], 'dog': ['barky', 'Donald', 'Fikky']}

{'cat': ['spooky', 'fat tail'],
 'dog': ['barky', 'Donald', 'Fikky'],
 'horse': ['duke', 'bishop', 'knight']}

In [74]:
pets1['dog']


Out[74]:
['barky', 'Donald', 'Fikky']

In [78]:
pets1['horse'][2] # the second horse


Out[78]:
'knight'

We could als make a dict that allows to use the name of the pet as a key and then get the kind of pet


In [82]:
pets2 = {'spooky' : 'cat', 'fat tail' : 'cat', 'barky' : 'dog', 'Donald' : 'dog', 'Fikky' : 'dog',
        'duke' : 'horse','bishop' : 'horse', 'knight' : 'horse'}

In [84]:
pprint(pets2)


{'Donald': 'dog',
 'Fikky': 'dog',
 'barky': 'dog',
 'bishop': 'horse',
 'duke': 'horse',
 'fat tail': 'cat',
 'knight': 'horse',
 'spooky': 'cat'}

In [50]:
pprint(pets2) # pprint prints in a nicer formatted way


{'Donald': 'dog',
 'Fikky': 'dog',
 'barky': 'dog',
 'bishop': 'horse',
 'duke': 'horse',
 'fat tail': 'cat',
 'knight': 'horse',
 'spooky': 'cat'}

In [51]:
pets2['duke']


Out[51]:
'horse'

In [52]:
pets2['Fikky']


Out[52]:
'dog'

Dicts have methods. The most important of them are keys(), values() and items()

  • keys() yields an iterable keys objects
  • values() yields an iterable values object
  • itmes() yieds an iterable tuple object containing (key, value) pairs.

Iterable means, that the object can be used like in iterable like in loops: for key in pets2.keys():


In [53]:
print(pets1.keys())
print(pets2.keys())
print()
print(pets1.values())
print(pets2.values())
print()
print(pets1.items())
print()
print(pets2.items())


dict_keys(['cat', 'horse', 'dog'])
dict_keys(['Fikky', 'fat tail', 'duke', 'knight', 'Donald', 'bishop', 'spooky', 'barky'])

dict_values([['spooky', 'fat tail'], ['duke', 'bishop', 'knight'], ['barky', 'Donald', 'Fikky']])
dict_values(['dog', 'cat', 'horse', 'horse', 'dog', 'horse', 'cat', 'dog'])

dict_items([('cat', ['spooky', 'fat tail']), ('horse', ['duke', 'bishop', 'knight']), ('dog', ['barky', 'Donald', 'Fikky'])])

dict_items([('Fikky', 'dog'), ('fat tail', 'cat'), ('duke', 'horse'), ('knight', 'horse'), ('Donald', 'dog'), ('bishop', 'horse'), ('spooky', 'cat'), ('barky', 'dog')])

In [93]:
pets1.keys()
pets1.values()
pets1.items()


Out[93]:
dict_items([('cat', ['spooky', 'fat tail']), ('horse', ['duke', 'bishop', 'knight']), ('dog', ['barky', 'Donald', 'Fikky'])])

You see that these key objects look like lists but they are not. They are in fact immutable, which is necessary to guaranty the integrety of the dict. You can turn them into a list by passing them to the list() function.


In [94]:
print(list(pets1.keys()))
print(list(pets1.values()))
print(list(pets1.items())) # This is a list of tuples.


['cat', 'horse', 'dog']
[['spooky', 'fat tail'], ['duke', 'bishop', 'knight'], ['barky', 'Donald', 'Fikky']]
[('cat', ['spooky', 'fat tail']), ('horse', ['duke', 'bishop', 'knight']), ('dog', ['barky', 'Donald', 'Fikky'])]

You could also turn these dict_keys etc into tuples:


In [14]:
print(list(pets2.keys()))   # list because surrounded by square brackets (= mutable)
print(tuple(pets2.keys()))  # Tuple because surrounded by braces (= immutable)


['Fikky', 'knight', 'fat tail', 'barky', 'bishop', 'spooky', 'Donald', 'duke']
('Fikky', 'knight', 'fat tail', 'barky', 'bishop', 'spooky', 'Donald', 'duke')

The order in which the key-value pairs have been given to a dict has no meaning into the order in which these pairs are stored or to the order in which they are shown when the dict is printed. The order may be different for different computer systems and even python releases.


In [95]:
# The order does not matter, so the contents of these two dict are the same, the answer is True
{'dog' : 'barky', 'horse' : 'duke', 'cat' : 'fat tail'} == {'horse' : 'duke', 'cat' : 'fat tail', 'dog' : 'barky'}


Out[95]:
True

In [96]:
# This is not true for two lists with the same items but in different order
['dog', 'cat'] == ['cat', 'dog']


Out[96]:
False

In [17]:
# But is is true for a set:
{'dog', 'cat', 'horse'} == {'horse', 'dog', 'cat'}


Out[17]:
True

More advanced dicts would be dicts of dicts, that is a dict of which value is found by key1 while the value itself consists of a dict from which values can be looked up by key2. For instance, we may have a dict with key1 the name of the animal and key2 specifying properties of that particular animal, so we may ask pet['duke']['age'], pet['spooky']['color'] etc. For example


In [97]:
pet = {'duke' : {'kind' : 'horse', 'age': 11, 'color' : 'brown'},            
        'spooky' : {'kind': 'cat', 'age': 8, 'color': 'red'},
        'barky' : {'kind' : 'dog', 'age': 3, 'color': 'black'},
        'fat tail': {'kind' : 'cat', 'age' : 4, 'color': 'white'},
}

In [98]:
pet


Out[98]:
{'barky': {'age': 3, 'color': 'black', 'kind': 'dog'},
 'duke': {'age': 11, 'color': 'brown', 'kind': 'horse'},
 'fat tail': {'age': 4, 'color': 'white', 'kind': 'cat'},
 'spooky': {'age': 8, 'color': 'red', 'kind': 'cat'}}

In [99]:
pet['duke']


Out[99]:
{'age': 11, 'color': 'brown', 'kind': 'horse'}

In [19]:
pet['duke']['age']


Out[19]:
11

In [100]:
pet['spooky']['color']


Out[100]:
'red'

In [101]:
pet['spooky'].keys()


Out[101]:
dict_keys(['kind', 'color', 'age'])

In [102]:
pet['spooky'].values()


Out[102]:
dict_values(['cat', 'red', 8])

In [103]:
pet['spooky'].items()


Out[103]:
dict_items([('kind', 'cat'), ('color', 'red'), ('age', 8)])

You can iterate over the dict, that is over its keys

printing the pet shows its keys


In [110]:
for p in pet: # is should be for p in pet.keys() but that is not needed.
    print("My animal {} is {} years old".format(pet[p]['kind'], pet[p]['age']))


My animal cat is 4 years old
My animal horse is 11 years old
My animal cat is 8 years old
My animal dog is 3 years old

In [111]:
'duke' in pet # is 'duke' one of the pets? (this check the keys)


Out[111]:
True

In [27]:
for p in pet:  # iterate over the keys of pet
    print(pet[p])  # print the contents of pet[p], the pet with key p
    #print(p['color'])


{'age': 3, 'color': 'black', 'kind': 'dog'}
{'age': 4, 'color': 'white', 'kind': 'cat'}
{'age': 8, 'color': 'red', 'kind': 'cat'}
{'age': 11, 'color': 'brown', 'kind': 'horse'}

In [28]:
for p in pet.keys():  # same thing, using the keys explicitly, but this is not necessary `p in pet` is enough
    print(pet[p])  # print the contents of pet[p], the pet with key p


{'age': 3, 'color': 'black', 'kind': 'dog'}
{'age': 4, 'color': 'white', 'kind': 'cat'}
{'age': 8, 'color': 'red', 'kind': 'cat'}
{'age': 11, 'color': 'brown', 'kind': 'horse'}

Now ask a question, like, which pets have age less than 7 years?


In [114]:
age = 7
youngPets = []  # start with an empty list
for p in pet:
    if pet[p]['age'] < age:
        youngPets.append(p)

print(youngPets)
print()
print('The pets {} are all less than {} years old.'.format(youngPets, age))


['fat tail', 'barky']

The pets ['fat tail', 'barky'] are all less than 7 years old.

We can generate this list also with a so-called list comprehension.

First generate a list of all pets in the dict using list comprehension:


In [115]:
[p for p in pet]


Out[115]:
['fat tail', 'duke', 'spooky', 'barky']

Then add the age condition to filter out the younger pets:


In [118]:
[p for p in pet if pet[p]['age'] < age]


Out[118]:
['fat tail', 'barky']

Hence:


In [64]:
younPets = [p for p in pet if pet[p]['age']<age]

print('The pets {} are all less than {} years old.'.format(youngPets, age))


The pets ['fat tail', 'barky'] are all less than 7 years old.

In conclusion, the entire cell with for loop is now replaced by a single list comprehension.

Dict comprehsions and set comprehensions will be used next in a more advanced example.


In [119]:
import pdb
import inspect

def myfunc(kind, beast, *args, **kwargs):
    #pdb.set_trace()
    print("What enters the function {} ?".format(inspect.stack()[0][3]))
    print("Here it is:")
    print("   kind   = ", kind)
    print("   beast  = ", beast)
    print("   args   = ", args)
    print("   kwargs = ", kwargs)
    print()
    print(("My " + "{} " + "{} " + "{} " + "to " + "{} " + "in " + "{} " + "{}.\n").
              format(kind, beast, args[0], args[1], kwargs['where'], kwargs['when']))
        
        
myfunc('dear', 'dog',  "loves", 'walk', speed='slowly', dist=2, where='the garden', when='tonight')


What enters the function myfunc ?
Here it is:
   kind   =  dear
   beast  =  dog
   args   =  ('loves', 'walk')
   kwargs =  {'where': 'the garden', 'speed': 'slowly', 'dist': 2, 'when': 'tonight'}

My dear dog loves to walk in the garden tonight.

Explanation of inspect.stack()

  • st = inspect.stack() given the stack.
  • top = st[0] is the top of the stack, i.e. the last call.
  • Its fourth attribute i.e. index 3 of the top top[3] is the name of the current file

hence

  • current_filename = inspect.stack()[0][3]

Example below:


In [66]:
top = inspect.stack()[0]

for s in top:
    print(s)


<frame object at 0x106a46128>
<ipython-input-66-5ecd4762d6fb>
1
<module>
['\n']
-1

In [67]:
import inspect

def foo():
   print(inspect.stack()[0][3])

foo()


foo

In [ ]: