Multiple levels of keys and values in Python

The value assigned to a key in a dictionary can itself be another dictionary

creatures = dict()
creatures['birds'] = dict()
creatures['birds']['eagle'] = dict()
creatures['birds']['eagle']['female'] = 0
creatures['birds']['eagle']['female'] += 1

You need to explicitly create each dictionary, though. Unlike Perl, Python does not automatically create a dictionary when you attempt to treat the value of an unassigned key as such.

Unless, of course, you use a defaultdict:

from collections import defaultdict
creatures = defaultdict( lambda: defaultdict(lambda: defaultdict( int )))
creatures['birds']['eagle']['female'] += 1

For arbitrary levels of nesting, you can use this recursive definition

dd = defaultdict( lambda: dd )
creatures = dd
creatures['birds']['eagle']['female'] = 0

In this case, you do need to explicitly initialize the integer value, since otherwise the value of creatures['birds']['eagle']['female'] will be assumed to be another defaultdict:

>>> creatures = dd
>>> type(creatures['birds']['eagle']['female'])
<class 'collections.defaultdict'>

If you just have to "count" things -- and assuming the data file contains all the required level of "hashes" -- that will do the trick:

import collections

result = collections.defaultdict(int)

with open("beast","rt") as f:
    for line in f:
        hashes = line.split()
        key = '-'.join(hashes)
        result[key] += 1

print result

Producing the result:
defaultdict(<type 'int'>, {'Mammals-whales-Male': 1, 'Birds-Eagle-Female': 2})

If you require nested dictionary -- post-processing of that result is still possible...