6

Как преобразовать вложенный словарь Python в объект?

1

Я ищу элегантный способ доступа к данным в словаре, содержащем вложенные словари и списки, используя синтаксис, похожий на объекты в 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

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

5 ответ(ов)

1

В вашем коде реализация класса obj позволяет динамически создавать атрибуты на основе ключей словаря. Давайте подробно разберем, как это работает и что происходит в каждом шаге:

  1. Конструктор __init__ класса obj:

    • Этот метод принимает словарь d в качестве аргумента.
    • Затем он итерируется по паре ключ-значение k, v в этом словаре.
  2. Условие для ключей:

    • Если ключ k является списком или кортежем (isinstance(k, (list, tuple))), то для каждого элемента x в соответствующем значении v, если x является словарем, создается новый объект obj с помощью рекурсии (obj(x)), иначе элемент сохраняется без изменений.
    • Если k не является списком или кортежем, проверяется, является ли значение v словарем. Если да, то создается новый объект obj, в противном случае значение сохраняется как есть.
  3. Пример использования:

    • При создании экземпляра x с помощью словаря d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}, атрибуты a, b и d будут созданы:
      • x.a будет равно 1
      • x.b будет объектом obj, который содержит c со значением 2, и его можно получить через x.b.c
      • x.d будет списком, где второй элемент — это объект obj, содержащий ключ foo со значением "bar", который можно получить через x.d[1].foo

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

Вот пример использования в вашем коде:

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
x = obj(d)

print(x.b.c)  # Вывод: 2
print(x.d[1].foo)  # Вывод: 'bar'

Этот подход может быть полезен для работы с JSON-подобными структурами, где данные представлены в виде вложенных словарей и списков.

0

Для того чтобы создать новый объект на основе словаря с помощью функции type, вы можете использовать следующий код:

x = type('new_dict', (object,), d)

Теперь добавим рекурсию в эту функцию, чтобы она могла обрабатывать вложенные словари и другие структуры данных.

Редактирование: Вот как я бы это реализовал:

>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
    top = type('new', (object,), d)
    seqs = (tuple, list, set, frozenset)
    for i, j in d.items():
        if isinstance(j, dict):
            setattr(top, i, obj_dic(j))
        elif isinstance(j, seqs):
            setattr(top, i, 
                type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
        else:
            setattr(top, i, j)
    return top

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

В этом коде мы определяем функцию obj_dic, которая принимает словарь d и создает новый класс на его основе. Если элемент в словаре является вложенным словарем или коллекцией (списком, кортежем и т.д.), мы рекурсивно преобразуем его в новый объект. Это позволяет вам делать доступ к элементам, как если бы они были атрибутами объекта.

0

Этот код представляет собой реализацию класса Struct, который позволяет создавать удобные объекты из вложенных структур данных, таких как словари и списки, как в Python 2, так и в Python 3.

Описание

Класс Struct может использоваться для создания объектов, структура которых соответствует структуре переданного словаря. Например, вы можете передать вложенные словари, и для каждой пары ключ-значение автоматически создаются соответствующие атрибуты объекта.

Примеры использования

Python 3

data = {
    'name': 'John',
    'age': 30,
    'attributes': {
        'height': 180,
        'weight': 75
    }
}

person = Struct(data)
print(person.name)  # Вывод: John
print(person.attributes.height)  # Вывод: 180

Python 2

data = {
    'name': 'John',
    'age': 30,
    'attributes': {
        'height': 180,
        'weight': 75
    }
}

person = Struct(data)
print person.name  # Вывод: John
print person.attributes.height  # Вывод: 180

Как это работает

  1. Конструктор __init__ принимает на вход словарь data и создает атрибуты для каждого элемента в этом словаре.
  2. Метод _wrap обрабатывает вложенные структуры:
    • Если значение является списком, кортежем, множеством или неизменяемым множеством, оно будет рекурсивно обработано.
    • Если значение является словарем, создается новый объект Struct.
    • В противном случае возвращается само значение.

Примечание

Класс Struct можно использовать с любой последовательностью, словарем или значением любой глубины, благодаря рекурсивной обработке. Это делает ваш код более читаемым и позволяет работать с комплексными структурами данных, как с атрибутами объекта.

0

Вы можете использовать модуль json из стандартной библиотеки вместе с пользовательским обработчиком объектов:

import json

class DictObject(object):
    def __init__(self, dict_):
        self.__dict__.update(dict_)

    @classmethod
    def from_dict(cls, d):
        return json.loads(json.dumps(d), object_hook=DictObject)

Пример использования:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> o = DictObject.from_dict(d)
>>> o.a
1
>>> o.b.c
2
>>> o.d[0]
'hi'
>>> o.d[1].foo
'bar'

Обратите внимание, что это не строго неизменяемо, как в случае с namedtuple, т.е. вы можете изменять значения — но не структуру:

>>> o.b.c = 3
>>> o.b.c
3

Таким образом, DictObject предоставляет удобный способ работы с данными в формате JSON, позволяя доступ к элементам как атрибутам объекта, с возможностью изменения значений.

0

Вот перевод на русский в стиле ответа на StackOverflow:


На основании предыдущих примеров, я разработал следующий класс, который позволяет строить и представлять объекты:

class Struct:
    """Рекурсивный класс для построения и представления объектов."""

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

    def __getitem__(self, val):
        return self.__dict__[val]

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

Данный класс позволяет создать объект с помощью словаря, включая вложенные структуры. Пример использования:

data = {'name': 'Alice', 'age': 30, 'address': {'city': 'Moscow', 'zip': '123456'}}
struct_obj = Struct(data)

print(struct_obj)  # Вывод: {name : 'Alice', age : 30, address : {city : 'Moscow', zip : '123456'}}
print(struct_obj['name'])  # Вывод: Alice

Таким образом, вы получаете удобный способ работы с данными, используя простую и понятную структуру.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь