Преобразовать вложенный Python dict в объект? - PullRequest
490 голосов
/ 20 августа 2009

Я ищу элегантный способ получения данных с использованием доступа к атрибутам в файле с некоторыми вложенными документами и списками (т. Е. Синтаксис объекта в стиле javascript).

Например:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

Должно быть доступно следующим образом:

>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar

Я думаю, это невозможно без рекурсии, но что было бы хорошим способом получить стиль объекта для диктов?

Ответы [ 34 ]

0 голосов
/ 22 октября 2013

Это еще один альтернативный способ преобразования списка словарей в объект:

def dict2object(in_dict):
    class Struct(object):
        def __init__(self, in_dict):
            for key, value in in_dict.items():
                if isinstance(value, (list, tuple)):
                    setattr(
                        self, key,
                        [Struct(sub_dict) if isinstance(sub_dict, dict)
                         else sub_dict for sub_dict in value])
                else:
                    setattr(
                        self, key,
                        Struct(value) if isinstance(value, dict)
                        else value)
    return [Struct(sub_dict) for sub_dict in in_dict] \
        if isinstance(in_dict, list) else Struct(in_dict)
0 голосов
/ 08 января 2013

Мой словарь имеет следующий формат:

addr_bk = {
    'person': [
        {'name': 'Andrew', 'id': 123, 'email': 'andrew@mailserver.com',
         'phone': [{'type': 2, 'number': '633311122'},
                   {'type': 0, 'number': '97788665'}]
        },
        {'name': 'Tom', 'id': 456,
         'phone': [{'type': 0, 'number': '91122334'}]}, 
        {'name': 'Jack', 'id': 7788, 'email': 'jack@gmail.com'}
    ]
}

Как видно, у меня есть вложенные словари и список диктов . Это связано с тем, что addr_bk был декодирован из данных буфера протокола, которые были преобразованы в python dict с использованием lwpb.codec. Есть необязательное поле (например, email =>, где ключ может быть недоступен) и повторяющееся поле (например, phone => преобразовано в список dict).

Я перепробовал все предложенные выше решения. Некоторые плохо обрабатывают вложенные словари. Другие не могут легко распечатать детали объекта.

Лучше всего работает только решение dict2obj (dict) от Dawie Strauss.

Я немного улучшил его, когда ключ не может быть найден:

# Work the best, with nested dictionaries & lists! :)
# Able to print out all items.
class dict2obj_new(dict):
    def __init__(self, dict_):
        super(dict2obj_new, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj_new(it)
            elif isinstance(item, dict):
                self[key] = dict2obj_new(item)

    def __getattr__(self, key):
        # Enhanced to handle key not found.
        if self.has_key(key):
            return self[key]
        else:
            return None

Затем я проверил это с помощью:

# Testing...
ab = dict2obj_new(addr_bk)

for person in ab.person:
  print "Person ID:", person.id
  print "  Name:", person.name
  # Check if optional field is available before printing.
  if person.email:
    print "  E-mail address:", person.email

  # Check if optional field is available before printing.
  if person.phone:
    for phone_number in person.phone:
      if phone_number.type == codec.enums.PhoneType.MOBILE:
        print "  Mobile phone #:",
      elif phone_number.type == codec.enums.PhoneType.HOME:
        print "  Home phone #:",
      else:
        print "  Work phone #:",
      print phone_number.number
0 голосов
/ 14 июня 2019

Преобразование dict в object

from types import SimpleNamespace

def dict2obj(data):
    """将字典对象转换为可访问的对象属性"""
    if not isinstance(data, dict):
        raise ValueError('data must be dict object.')

    def _d2o(d):
        _d = {}
        for key, item in d.items():
            if isinstance(item, dict):
                _d[key] = _d2o(item)
            else:
                _d[key] = item
        return SimpleNamespace(**_d)

    return _d2o(data)

Ссылочный ответ

0 голосов
/ 22 августа 2012

У меня были некоторые проблемы с тем, что __getattr__ не вызывается, поэтому я создал новую версию класса стилей:

class Struct(object):
    '''The recursive class for building and representing objects with.'''
    class NoneStruct(object):
        def __getattribute__(*args):
            return Struct.NoneStruct()

        def __eq__(self, obj):
            return obj == None

    def __init__(self, obj):
        for k, v in obj.iteritems():
            if isinstance(v, dict):
                setattr(self, k, Struct(v))
            else:
                setattr(self, k, v)

    def __getattribute__(*args):
        try:
            return object.__getattribute__(*args)
        except:            
            return Struct.NoneStruct()

    def __repr__(self):
        return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for 
(k, v) in self.__dict__.iteritems()))

Эта версия также имеет добавление NoneStruct, которое возвращается при вызове атрибута, который не установлен. Это позволяет проводить тестирование None для проверки наличия атрибута. Очень полезно, когда точный ввод dict неизвестен (настройки и т.д.).

bla = Struct({'a':{'b':1}})
print(bla.a.b)
>> 1
print(bla.a.c == None)
>> True
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...