Python автоматически вставленный dict - PullRequest
1 голос
/ 17 июня 2020

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

Frozendict не кажется для этого, по крайней мере, pympler.asizeof не показывает меньший объем памяти.

Обновление: У меня есть такие объекты

{ 
  "titles": [{"title": x, "subtitle": y}, {"title": v, "subtitle": z}],
  "authors": [{"name": x, "location": y}, {"name": z}],
  "keywords": [{"type": a, "content": b}, ...],
  "prices": a,
   ...
}

Особенно ключевые слова довольно часто используется и потребляет значительную часть памяти. До сих пор я преобразовал ключевые слова в сегментный класс, но хотел знать, смогу ли я каким-то образом, но всю эту структуру как своего рода фиксированный dict, где я говорю, что ничего не изменится, поэтому теперь оптимизируйте объем памяти для этого.

1 Ответ

0 голосов
/ 22 июня 2020

Пока я дошел до

def compress_dict(slots):
    class SlottedDict:
        __slots__ = list(slots.keys())
        
        def __init__(self, slots):
            for key in slots:
                if isinstance(slots[key], dict):
                    SlottedDict.__dict__[key].__set__(self, compressDict(slots[key]))
                elif isinstance(slots[key], list):
                    if all([isinstance(item, dict) for item in slots[key]]):
                        slotted_list = []
                        for item in slots[key]:
                            slotted_list.append(compressDict(item))
                        SlottedDict.__dict__[key].__set__(self, slotted_list)
                    else:
                        SlottedDict.__dict__[key].__set__(self, slots[key])
                else:
                    SlottedDict.__dict__[key].__set__(self, slots[key])
                    
        def get(self, item, default=None):
            return SlottedDict.__dict__[item].__get__(self, SlottedDict)
     
        def to_json(self):
            json_dict = {}
            for key in SlottedDict.__dict__['__slots__']:
                item = SlottedDict.__dict__[key].__get__(self, SlottedDict)
                if type(item).__name__  ==  "SlottedDict":
                    item = item.to_json()
                elif isinstance(item, list):
                    item = [i.to_json() if type(i).__name__  ==  "SlottedDict" else i for i in item]
                json_dict[key] = item
            return json_dict

    return SlottedDict(slots)

Я не уверен, смогу ли я как-то это улучшить, но пока, похоже, это работает. В моем примере я могу получить доступ к dict через

>>> d = { 
  "titles": [{"title": "x", "subtitle": "y"}, {"title": "v", "subtitle": "z"}],
}

>>> compress_dict(d).titles
[{"title": "x", "subtitle": "y"}, {"title": "v", "subtitle": "z"}]

>>> print(asizeof(d), asizeof(compress_dict(d)))
1200 480

>>> print(compressDict(d).to_json() == d)
True

Мне просто интересно, что в python stdlab ничего подобного нет, по крайней мере, я ничего не нашел ...

Edit :

Я обнаружил, что все эти классы как-то тоже нужно сохранять. Мой тест был следующего типа: я сравнил использование ОЗУ для некоторого простого dict ({"a": "b", "c": "d"}) с a) compress_dict, b) некоторым классом с слотами, содержащим только слоты. a и c, и c) диктуют сами себя. Все это с 1_000_000 dicts в списке. а) привело к 2,6 ГБ, б) до 98 МБ и c) до 270 МБ. Таким образом, большой недостаток заключается в том, что этот фрагмент кода не может повторно использовать существующие автоматически созданные классы ...

...