Форум сайта python.su
class DeepDict(dict): def __init__(self, *args, **kwargs): self.default = kwargs.pop("default") super(DeepDict, self).__init__(*args, **kwargs) def __getitem__(self, item): try: value = super(DeepDict, self).__getitem__(item) if isinstance(value, dict): return DeepDict(value, default=self.default) else: return value except KeyError: return self.default def __repr__(self): return "DeepDict: {}".format(super(DeepDict, self).__repr__()) dct = {"a": {"b": {"c": 0}}} d = DeepDict(dct, default=10) print(d["a"]["b"]["c"]) print(d["a"]["FF"])
Офлайн
Подумал, что наверно более правильный способ не с отдельными полями работать, а определять структуру со значениями по умолчанию, тогда наверно такой вариант будет правильным
context = {**defaults, **user}
context = defaults.copy() context.update(user)
Отредактировано worldmind (Янв. 5, 2017 09:47:09)
Офлайн
ABKorotky
Правда, для рекурсивной инициализации не совсем подходит
d = defaultdict(lambda:defaultdict(list))
v = TE(lambda: x[2][3], 2)
Отредактировано doza_and (Янв. 5, 2017 10:01:14)
Офлайн
worldmindА, тут подсказывают что со вложенными так не сделать
Подумал, что наверно более правильный способ не с отдельными полями работать, а определять структуру со значениями по умолчанию, тогда наверно такой вариант будет правильным
Отредактировано worldmind (Янв. 5, 2017 09:48:37)
Офлайн
Никто и не говорит, что есть проблема )
Насколько я понял изначальные условия сей ишью - нужно иметь механизм установки дефолтного значения для словаря некоторой структуры.
И вариантов действительно 100500!
Всё зависит от потребностей.
1) Простой словарь с единичным уровнем вложенности ключей.
Вариантов предложили массу, начиная от использования .get(), .update(), .setdefault() - выбирай любой!
Какие-то варианты потребуется везде по коду юзать. Это я про .get() и .setdefault(). Это нехорошо потому как логика алгоритма будет “размазываться” логикой доступа к ключам.
Варианты с .update() будет интересен при инстанцировании. Профит в атомарности и разовости такой операции.
2) Более сложный вариант с известной структурой и известным уровнем вложенности. Подойдут те же операции, что обозначены выше. Нужно будет позаботиться только о том, чтобы при создании под-словаря передать ему необходимое дефолтное значение.
3) Обобщённый вариант: есть некая структура дефолтных значений произвольной вложенности. Вот тут будут интересны вариации DeepDict, предложенные FishHook (сам что-то похожее велосипедил). Чем хорош этот подход: логика доступа к ключам (и вложенным) будет инкапсулирована в недрах класса, и в месте использования не придётся “разбодяживать” основной алгоритм разного рода проверками - ты просто обращается к ключу и будешь уверен, что получишь дефолтное значение.
Что же касается новых фишечек, то тут очень сильно зависит от степени “старости” проекта и зависимостях на внешние пакеты. Далеко не все проекты могут похвастаться использованием в проде пайтона версии даже 3.5 с async def вместо @coroutine и прочими новшествами (async for сюда же)
Офлайн
раз обсуждение продолжается поясню
def TE(f, default_value): try: return f() except: return default_value a={2:{3:"a"}} b=TE(lambda: a[2][4], 45)
Отредактировано doza_and (Янв. 5, 2017 10:41:45)
Офлайн
doza_andну я такой выше и делал, только в и инфиксной форме
раз обсуждение продолжается поясню
Офлайн
Но сейчас я согласен с тем, что наверно мердж двух вложенныйх хешей это даже более удобный вариант, да только не нахожу в питоне готовой функции для этого
Офлайн
worldmind
ChainMap ?
Офлайн
4kpt_IVнадо глянуть
worldmindChainMap ?
>>> import dpath.util >>> from copy import deepcopy >>> default_struct = {'key': {'key1': 0, 'key2': 0}} >>> struct = {'key': {'key1': 666}} >>> merged = deepcopy(default_struct) >>> dpath.util.merge(merged,struct) >>> merged {'key': {'key1': 666, 'key2': 0}}
Офлайн