Самый компактный способ сериализации объекта, который содержит другие объекты в Python? - PullRequest
0 голосов
/ 01 июля 2018

Какой самый компактный способ сериализации объекта, который содержит другие объекты или даже вложенные коллекции других объектов в python?

Подробнее:

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

Мне нужно передать некоторые из этих коллекций через API REST с использованием файлов json.

Мы можем использовать пример как ниже.

Пример кода:

from typing import List, Dict


class Organization:
    def __init__(self, name):
        self.name = name
        self.employees = []  # type: List[Person]


class Person:
    def __init__(self, name: str):
        self.name = name
        self.qualification = ""
        self.pets = []  # type: List[Pet]


class Pet:
    def __init__(self, name: str, species: str):
        self.species = species
        self.name = name


if __name__ == "__main__":
    pets_dict = {"Simba": "cat", "Winnie": "bear", "Tigger": "bear", "Drogon": "dragon",
                "Rhaegal": "dragon", "Viserion":"dragon",  "Ghost": "wolf"}
    people_dict = ["Walt", "Christopher", "Dany", "Jon"]
    pets_obj = {p: Pet(p, pets_dict[p]) for p in pets_dict}  # type: Dict[str, Pet]
    people_obj = {p: Person(p) for p in people_dict}  # type: Dict[str, Person]
    people_obj["Walt"].pets = [pets_obj["Simba"],]
    people_obj["Christopher"].pets = [pets_obj["Winnie"], pets_obj["Tigger"]]
    people_obj["Dany"].pets = [pets_obj["Drogon"], pets_obj["Rhaegal"], pets_obj["Viserion"]]
    people_obj["Jon"].pets = [pets_obj["Ghost"], ]
    organization = Organization("Stories")
    organization.employees = list(people_obj.values())

    print(vars(organization))

Выход:

{'name': 'Stories', 'employees': [<__main__.Person object at 0x00000000025DFDD8>, <__main__.Person object at 0x00000000025E6630>,  <__main__.Person object at 0x00000000025E6AC8>, <__main__.Person object at 0x00000000025E6B38>]}

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

найденные решения:

  1. Существует этот вопрос-ответ . Он содержит 2 предложения: первое - только для простых случаев с использованием dumps(organization.__dict__). Это не работает в примере. Второй метод заключается в написании класса кодирования, который аналогичен решению (2) ниже. Это неплохое решение, но посмотрите мое «Почему я думаю, что должен быть лучший путь» ниже.

  2. Используйте json.dump (или дампы) и включите сериализатор для каждого пользовательского класса.

    def my_serializer(obj):
        if type(obj) in (Organization, Person, Pet):
            return vars(obj)
        else:
            return obj
    

тогда делай

    print(dumps(organization, default=my_serializer))
  1. Напишите метод self.export для каждого класса, который будет сериализовать себя, и для любых коллекций пользовательских классов, которые он содержит, при сериализации вызовите метод экспорта этого класса.

Почему я думаю, что должен быть лучший способ:

По сути, я ищу глубокий vars (как есть deepcopy). Я могу себе представить, что многие хотели такую ​​вещь, поэтому я ожидаю, что существует простое и ясное решение. Я просто не мог найти путь к Google, поэтому я обращаюсь к сообществу.

1 Ответ

0 голосов
/ 03 июля 2018

Вариант 2 - передача сериализатора на json.dumps - правильный способ сделать это. Вы предоставляете сериализатор, json.dumps обрабатывает повторение через граф объектов.

Там нет значения в deep_vars, если вы не хотите словарь вашего графа объектов, но вы не хотите словарь, вы просто JSON.

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