Как заставить glom работать с объектами типа dict

Glom ( https://glom.readthedocs.io/en/latest/), помимо прочего, предназначен для

основанный на пути доступ для вложенных структур

Но как вы заставляете это работать для вложенных структур помимо диктов?

Рассмотрим следующий класс (намеренно не фактический collection.abc.Mapping, для простоты:

class MyMap: 
    def __init__(self, d):
        self.d = d
    def __getitem__(self, k):
        """just delegating"""
        v = self.d[k]
        if isinstance(v, (dict, MyMap)):
            return MyMap(v)
        else:
            return v

Это работает:

m = MyMap({'a': {'b': {'c': 'd'}}})
assert m['a']['b']['c'] == 'd'

Но это не так:

from glom import glom
assert glom(m, 'a.b.c') == 'd'

Я получаю ошибку:PathAccessError: could not access 'a', part 0 of Path('a', 'b', 'c'), got error: AttributeError("'MyMap' object has no attribute 'a'")

Более конкретно, как можно указать:

  • что такое узел (то есть объект, который может быть отброшен дальше)
  • ключевой итератор (как разбить путь на ключи)
  • средство получения элемента (как данные извлекаются из ключа)

В случае, если это поможет, вот та функция, которую я ищу, чтобы удовлетворить glom:

dot_str_key_iterator = lambda p: p.split('.')
bracket_getter = lambda obj, k: obj[k]

def simple_glom(target, spec, 
                node_types=(dict,), 
                key_iterator=dot_str_key_iterator,
                item_getter=bracket_getter
               ):
    for k in key_iterator(spec):
        target = item_getter(target, k)
        if not isinstance(target, node_types):
            break
    return target

Эта функция не имеет всех наворотов, но позволяет мне:

m = MyMap({'a': {'b': {'c': 'd'}}})
simple_glom(m, 'a.b.c', node_types=(MyMap,))

Или для крайнего примера, использующего все параметризации:

from types import FunctionType
from functools import partial

attr_glom = partial(simple_glom, 
                    node_types=(FunctionType, type), 
                    key_iterator=lambda p: p.split('/'), 
                    item_getter=getattr)
assert attr_glom(MyMap, '__getitem__/__doc__') == 'just delegating'

0 ответов

Это отличные вопросы! Я сделаю все возможное, чтобы разбить их по одному:

Как указать, что объект можно слепить?

Когда вы говорите здесь "glom", я предполагаю, что вы имеете в виду "доступ".

Python имеет очень богатую модель данных, и хотя обычно термин "доступ" имеет интуитивно понятное значение в любом контексте, угадывать его может быть дорого и рискованно. Подход glom к этому заключается в предоставлении явных регистрационных API.

Как указать ключевой итератор?

Если вы хотите разделить путь (например,'a.b.c' из glom(target, 'a.b.c')) В структурированных ключей (и операции), которые используются для доступа, путь, я бы рекомендовал смотреть на Pathтип, в частности,Path.from_text() а также path.items().

Если вы хотите посмотреть на объект и выяснить, какие пути существуют внутри объекта, это сложнее.

На момент написания glomпо-прежнему в первую очередь предназначен для доступа и построения известных структур с некоторыми возможностями для значений по умолчанию / ветвления. Лучшее, что я могу предложить для полной бесконтекстной итерации всех возможных путей, - это remap (поваренная книга). Обратите внимание, что remap не имеет возможности плагина / регистрации glom, но он действительно работает из коробки для итерации glommable путей в общих типах данных Python, как показано в этом примере (соответствующийglom() звонок делается чуть ниже).

Как указать, как данные извлекаются из ключа?

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

На случай, если ваше определение "получить" противоречит встроенному getрегистрации, вы можете переопределить ее или указать новую операцию, которую можно зарегистрировать с помощью register_op, (например, как assign операция была добавлена).

Опять же, отличные вопросы, здесь вы действительно используете мощь Python. Надеюсь это поможет!

Другие вопросы по тегам