A lot of times in Perl, I’ll do something like this:
$myhash{foo}{bar}{baz} = 1
How would I translate this to Python? So far I have:
if not 'foo' in myhash:
myhash['foo'] = {}
if not 'bar' in myhash['foo']:
myhash['foo']['bar'] = {}
myhash['foo']['bar']['baz'] = 1
Is there a better way?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
If the amount of nesting you need is fixed, collections.defaultdict is wonderful.
e.g. nesting two deep:
myhash = collections.defaultdict(dict) myhash[1][2] = 3 myhash[1][3] = 13 myhash[2][4] = 9
If you want to go another level of nesting, you’ll need to do something like:
myhash = collections.defaultdict(lambda : collections.defaultdict(dict)) myhash[1][2][3] = 4 myhash[1][3][3] = 5 myhash[1][2]['test'] = 6
edit: MizardX points out that we can get full genericity with a simple function:
import collections
def makehash():
return collections.defaultdict(makehash)
Now we can do:
myhash = makehash() myhash[1][2] = 4 myhash[1][3] = 8 myhash[2][5][8] = 17 # etc
Method 2
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
Testing:
a = AutoVivification() a[1][2][3] = 4 a[1][3][3] = 5 a[1][2]['test'] = 6 print a
Output:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
Method 3
Is there a reason it needs to be a dict of dicts? If there’s no compelling reason for that particular structure, you could simply index the dict with a tuple:
mydict = {('foo', 'bar', 'baz'):1} # Initializes dict with a key/value pair
mydict[('foo', 'bar', 'baz')] # Returns 1
mydict[('foo', 'unbar')] = 2 # Sets a value for a new key
The parentheses are required if you initialize the dict with a tuple key, but you can omit them when setting/getting values using []:
mydict = {} # Initialized the dict
mydict['foo', 'bar', 'baz'] = 1 # Sets a value
mydict['foo', 'bar', 'baz'] # Returns 1
Method 4
I guess the literal translation would be:
mydict = {'foo' : { 'bar' : { 'baz':1}}}
Calling:
>>> mydict['foo']['bar']['baz']
gives you 1.
That looks a little gross to me, though.
(I’m no perl guy, though, so I’m guessing at what your perl does)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0