Python: Создан вложенный словарь из списка путей - PullRequest
0 голосов
/ 29 апреля 2010

У меня есть список кортежей, который выглядит примерно так (здесь упрощенно, существует более 14 000 таких кортежей с более сложными путями, чем Obj.part)

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

Где Obj идет от 1 до 1000, от 0 до 2000. Все эти «ключи» имеют словарь спецификаций, связанных с ними, которые служат справочной информацией для проверки другого двоичного файла. DECTS спецификация содержит информацию, такую ​​как смещение бита, размер бита и тип C данных, на которые указывает путь ObjK.partN.

Например: Obj4.part500 может иметь эту спецификацию, {'size': 32, 'offset': 128, 'type': 'int'}, которая позволит мне узнать это для доступа к Obj4.part500 в двоичном файле Я должен распаковать 32 бита со смещения 128.

Итак, теперь я хочу взять мой список строк и создать вложенный словарь, который в упрощенном случае будет выглядеть так

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

Для этого я сейчас делаю две вещи: 1. Я использую класс dotdict, чтобы иметь возможность использовать точечную нотацию для словаря get / set. Этот класс выглядит так:

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

Метод создания вложенных «дотдиктов» выглядит следующим образом:

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

Тогда я просто делаю что-то вроде:

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

Итак, в итоге
self.lookup.Obj4.part500 указывает на спецификацию.

Есть ли лучший (более питонический) способ сделать это?

1 Ответ

7 голосов
/ 29 апреля 2010

Если вы не предпочитаете обращаться к спецификациям с точечной нотацией, попробуйте поместить их в словарь напрямую. В приведенном ниже коде имя d отслеживает самый внутренний словарь, посещаемый по пути:

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

Если у вас есть только две части на пути (скажем, ObjN и partN), вы можете просто сделать это:

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