Как заставить 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. Надеюсь это поможет!