web-dev-qa-db-fra.com

Quelle est la meilleure façon d'initialiser un dict de dict en Python?

Beaucoup de fois en Perl, je ferai quelque chose comme ça:

$myhash{foo}{bar}{baz} = 1

Comment pourrais-je traduire cela en Python? Jusqu'à présent, j'ai:

if not 'foo' in myhash:
    myhash['foo'] = {}
if not 'bar' in myhash['foo']:
    myhash['foo']['bar'] = {}
myhash['foo']['bar']['baz'] = 1

Y a-t-il une meilleure façon?

78
mike
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

Essai:

a = AutoVivification()

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

print a

Sortie:

{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
94
nosklo

Si le nombre d'imbrication dont vous avez besoin est fixe, collections.defaultdict est merveilleux.

par exemple. imbriquant deux profondeurs:

myhash = collections.defaultdict(dict)
myhash[1][2] = 3
myhash[1][3] = 13
myhash[2][4] = 9

Si vous souhaitez passer à un autre niveau d'imbrication, vous devrez faire quelque chose comme:

myhash = collections.defaultdict(lambda : collections.defaultdict(dict))
myhash[1][2][3] = 4
myhash[1][3][3] = 5
myhash[1][2]['test'] = 6

edit: MizardX souligne que nous pouvons obtenir la pleine généricité avec une fonction simple:

import collections
def makehash():
    return collections.defaultdict(makehash)

Maintenant, nous pouvons faire:

myhash = makehash()
myhash[1][2] = 4
myhash[1][3] = 8
myhash[2][5][8] = 17
# etc
100
John Fouhy

Y a-t-il une raison pour laquelle ce doit être un dicton de dict? S'il n'y a pas de raison impérieuse pour cette structure particulière, vous pouvez simplement indexer le dict avec un 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

Les parenthèses sont obligatoires si vous initialisez le dict avec une clé Tuple, mais vous pouvez les omettre lorsque vous définissez/obtenez des valeurs en utilisant []:

mydict = {}                        # Initialized the dict
mydict['foo', 'bar', 'baz'] = 1    # Sets a value
mydict['foo', 'bar', 'baz']        # Returns 1
13
zweiterlinde

Je suppose que la traduction littérale serait:

 mydict = {'foo' : { 'bar' : { 'baz':1}}}

Appel:

 >>> mydict['foo']['bar']['baz']

vous donne 1.

Cela me semble un peu dégoûtant, cependant.

(Je ne suis pas un gars Perl, donc je devine ce que fait Perl)

2
Dana