13

Both Google and the online docs are not delivering much insight on my query, so I thought I would ask the community here.

In Perl, you can easily setup a hash-of-a-hash-of-a-hash and test the final key like so:

my $hash = {};
$hash{"element1"}{"sub1"}{"subsub1"} = "value1";
if (exists($hash{"element1"}{"sub1"}{"subsub1"})) {
   print "found value\n";
}

What's the 'best-practice' equivalent in Python?

martineau
  • 99,260
  • 22
  • 139
  • 249
jbb
  • 155
  • 1
  • 5

4 Answers4

16

The closest equivalent is probably something like the following:

import collections

def hasher():
  return collections.defaultdict(hasher)

hash = hasher()
hash['element1']['sub1']['subsub1'] = 'value1'
if 'subsub1' in hash['element1']['sub1']:
  print 'found value'
Alex Martelli
  • 762,786
  • 156
  • 1,160
  • 1,345
  • 3
    Note that `if sub1 in hash['phony']` creates a key `'phony'`. This might be problematic, especially since the OP wants to test if keys exist... – unutbu Jun 26 '10 at 03:24
  • @~unutbu: the OP asks: "test the *final* key", therefore `hash['element1']['sub1'] = dict(subsub1='value1')` will do. – jfs Jun 26 '10 at 03:56
  • Thanks, this is quite helpful. – jbb Jun 26 '10 at 08:32
5

As to whether this is a best practice in Python is up to debate:

hash = {}
hash['element1', 'sub1', 'subsub1'] = 'value'
if ('element1', 'sub1', 'subsub1') in hash:
    print "found value"

But, it certainly works and is very elegant, if it works for you.

The major drawback is that you don't have intermediate access. You can't do:

if ('element1', 'sub1') in hash:
   print "found value"
carl
  • 47,134
  • 17
  • 71
  • 81
  • 2
    You should explain what's happening. This is a single hash/dict with a 3-element [tuple](http://docs.python.org/library/functions.html#tuple) as a key. Really not the same thing, though you did somewhat indicate that with your second example. – Matthew Flaschen Jun 26 '10 at 03:32
  • Interesting way to handle the "drawback" (if you consider it to be such) in Alex Martelli's answer, pointed out by ~unutbu. – David Z Jun 26 '10 at 05:35
  • Indeed, this wasn't what I was looking for - but interesting nonetheless. Thanks for the tip. – jbb Jun 26 '10 at 08:33
2
from collections import defaultdict

tree = lambda: defaultdict(tree)

t = tree()

t[1][2][3] = 4
t[1][3][3] = 5
t[1][2]['test'] = 6

from wikipedia Autovivification

papalagi
  • 640
  • 2
  • 6
  • 19
0

I don't know if I'll get any agreement, but this is how I typically declare dictionaries of dictionaries:

someObj = {
  'element1': {
    'sub1': {
      'subsub1': 'value1'
    }
  }
}

As for checking for the presence of an element, I agree with this approach:

try:
  someObj['element1']['sub1']['subsub1']
except KeyError:
  print('no value found')
else:
  print('found value')
g.d.d.c
  • 41,737
  • 8
  • 91
  • 106