Как преобразовать вложенные словари в объекты с заданными типами для использования в API-обёртке?

Здравствуйте! <br/> <br/> Я разрабатываю библиотеку для обёртки API на Python и сталкиваюсь с задачей преобразования вложенных JSON-данных в объекты с атрибутами и типовыми аннотациями. Это позволит пользователям IDE получать автодополнение и проводить проверку типов. <br/> <br/> Вот пример получаемых данных: <br/> <pre><code class="python">example_data = {
    'fruits': {
        'apple': {
            'color': 'red',
            'taste': 'sweet',
            'quantity': 10,
            'prices': [
                {'store': 'Store A', 'price': 1.2},
                {'store': 'Store B', 'price': 1.3},
                {'store': 'Store C', 'price': 1.5}
            ]
        },
        # ... другие фрукты
    },
    # ... овощи
}</code></pre> <br/> <br/> В настоящий момент для доступа к данным я использую следующий способ: <br/> <pre><code class="python"># Через get или []
example_data['fruits']['apple']['color']</code></pre> <br/> <br/> Но я хочу иметь доступ к данным следующим образом: <br/> <pre><code class="python"># type(example_data.fruits.apple.quantity) is int == True (с аннотациями)
example_data.fruits.apple.quantity</code></pre> <br/> <br/> Пример цикла for для итерации по данным: <br/> <pre><code class="python">for item in example_data['fruits']['apple']['prices']:
    print(item['store'])</code></pre> <br/> <br/> Я бы хотел, чтобы это выглядело так: <br/> <pre><code class="python"># example_data.fruits.apple.prices is list == True
for item in example_data.fruits.apple.prices:
    print(item.store)</code></pre>
  • 12 октября 2024 г. 16:52
Ответы на вопрос 4
Для преобразования вложенных словарей в объекты с атрибутами и типовыми аннотациями в Python, можно использовать классы и метаклассы или проще — библиотеку `pydantic`. Она позволяет создавать модели данных, которые автоматически валидируют входящие данные, а также обеспечивают поддержку автодополнения и аннотаций типов.

Ниже представлен пример реализации такого подхода с использованием Pydantic:

```python
from typing import List
from pydantic import BaseModel


class Price(BaseModel):
    store: str
    price: float


class Fruit(BaseModel):
    color: str
    taste: str
    quantity: int
    prices: List[Price]


class FruitsData(BaseModel):
    apple: Fruit
    # добавьте сюда другие фрукты
    # banana: Fruit
    # orange: Fruit


class ExampleData(BaseModel):
    fruits: FruitsData
    # добавьте сюда другие категории, например, vegetables


# Пример полученных данных
example_data_dict = {
    'fruits': {
        'apple': {
            'color': 'red',
            'taste': 'sweet',
            'quantity': 10,
            'prices': [
                {'store': 'Store A', 'price': 1.2},
                {'store': 'Store B', 'price': 1.3},
                {'store': 'Store C', 'price': 1.5}
            ]
        },
        # другие фрукты...
    },
    # другие категории...
}

# Создание экземпляра модели из словаря
example_data = ExampleData(**example_data_dict)

# Пример доступа к данным
print(example_data.fruits.apple.color)  # вывод: red
print(example_data.fruits.apple.quantity)  # вывод: 10

# Цикл по ценам
for item in example_data.fruits.apple.prices:
    print(item.store)  # вывод: Store A, Store B, Store C
```

### Основные моменты:
1. **Модели данных**: Создаются классы, наследующие от `BaseModel`, каждый из которых представляет уровень вложенности ваших данных. Например, класс `Fruit` описывает фрукты, а класс `Price` описывает цены на фрукты.
  
2. **Типизация**: Используя аннотации типов, можно указать, какие типы данных ожидаются, что обеспечит автодополнение и проверку типов в IDE.

3. **Создание экземпляра**: Вы можете создать экземпляр модели данных, передав словарь, полученный с API. Pydantic автоматически проверит, что данные соответствуют заданным типам.

4. **Итерация**: Для итерации по ценам вы можете использовать обычный цикл `for`.

Эта модель легко адаптируется, и вы можете добавлять дополнительные свойства и вложенные структуры по мере необходимости.
можно использовать pydantic 
и потом описать модели, согласно нужным типам данных
Задачка не маленькая, и попыток ее решить ты не предоставил. Есть вот так вот  -  хочу вот так вот,  и все. 
Могу посоветовать книга Fluent Python глава 22 Dynamic Attributes and Properties.
В ней как раз на примере вложенного json объяснено предельно подробно, как решать подобные задачи.
можно использовать pydantic 
и потом описать модели, согласно нужным типам данных
Похожие вопросы