2010-04-29 7 views
0

J'ai une liste de tuples les ressemble à ceci (simplifié ici, il y a plus de 14 000 de ces tuples avec des chemins plus complexes que Obj.part)Python: Créé le dictionnaire imbriqué de la liste des chemins

[ (Obj1.part1, {<SPEC>}), (Obj1.partN, {<SPEC>}), (ObjK.partN, {<SPEC>}) ]

Où Obj va de 1 à 1000, partie de 0 à 2000. Ces "clés" ont toutes un dictionnaire de spécifications qui leur est associé et qui servent de références de recherche pour inspecter un autre fichier binaire. La spécification dict contient des informations telles que le décalage de bit, la taille de bit et le type C des données pointées par le chemin ObjK.partN. Par exemple: Obj4.part500 peut avoir cette spécification, {'size': 32, 'offset': 128, 'type': 'int'} ce qui me permettrait de savoir que pour accéder à Obj4.part500 dans le binaire Je dois déposer déballer 32 bits de l'offset 128.

donc, maintenant je veux prendre ma liste de chaînes et de créer un dictionnaire imbriqué qui, dans le cas simplifié ressemblera à ceci

data = { 'Obj1' : {'part1':{spec}, 'partN':{spec} }, 
     'ObjK' : {'part1':{spec}, 'partN':{spec} } 
     } 

pour ce faire, je Je fais actuellement deux choses, 1. J'utilise une classe dotdict pour être capable d'utiliser la notation par points pour le dictionnaire get/set. Cette classe ressemble à ceci:

class dotdict(dict): 
    def __getattr__(self, attr): 
     return self.get(attr, None) 
    __setattr__ = dict.__setitem__ 
    __delattr__ = dict.__delitem__ 

La méthode de création imbriquée "dotdict" s ressemble à ceci:

def addPath(self, spec, parts, base): 
    if len(parts) > 1: 
     item = base.setdefault(parts[0], dotdict()) 
     self.addPath(spec, parts[1:], item) 
    else: 
     item = base.setdefault(parts[0], spec) 
    return base 

Je viens de faire quelque chose comme:

for path, spec in paths: 
    self.lookup = dotdict() 
    self.addPath(spec, path.split("."), self.lookup) 

Ainsi, à la fin
self.lookup.Obj4.part500 points à la spécification.

Existe-t-il une meilleure façon (plus pythonique) de faire cela?

Répondre

7

Sauf si vous préférez accéder aux spécifications avec notation par points, essayez de les placer directement dans le dictionnaire. Dans le code ci-dessous, le nom d suit le dictionnaire le plus intérieur visité sur le chemin:

specs = {} 
for path, spec in paths: 
    parts = path.split('.') 
    d = specs 
    for p in parts[:-1]: 
     d = d.setdefault(p, {}) 
    d[parts[-1]] = spec 

Si vous avez seulement deux parties par voie (ObjN et partN dire), vous pouvez simplement faire ceci:

specs = {} 
for path, spec in paths: 
    [obj, part] = path.split('.') 
    specs.setdefault(obj, {})[part] = spec 
+0

+1 très bonne utilisation de setdefault – Rescommunes

Questions connexes