Доступ к python dict с помощью строки поиска нескольких ключей
Я хочу создать простой механизм поиска в python и хотел бы убедиться, что в обширных библиотеках python еще не было чего-то, что еще не сделано, прежде чем создавать его.
Я хочу взять dict, который отформатирован примерно так.
my_dict = {
"root": {
"secondary": {
"user1": {
"name": "jim",
"age": 24
},
"user2": {
"name": "fred",
"age": 25
}
}
}
}
и я пытаюсь получить доступ к данным с помощью десятичной нотации, которая была бы похожа на
root.secondary.user2
и верните, что в результате ответит обратно в ответ. Я думаю, что должно быть что-то, что делает это, и я мог бы написать один без особых трудностей, но я хочу убедиться, что не воссоздаю что-то, чего я могу потерять из документации. Благодаря
Ответы
Ответ 1
Нет ничего в стандартной библиотеке для этой цели, но это довольно легко закодировать сами:
>>> key = "root.secondary.user2"
>>> reduce(dict.get, key.split("."), my_dict)
{'age': 25, 'name': 'fred'}
Это подтверждает тот факт, что поиск ключа k
в словаре d
может быть записан как dict.get(d, k)
. Применение этого итерационного использования reduce()
приводит к желаемому результату.
Изменить. Для полноты трех функций для получения, установки или удаления ключей словаря с помощью этого метода:
def get_key(my_dict, key):
return reduce(dict.get, key.split("."), my_dict)
def set_key(my_dict, key, value):
key = key.split(".")
my_dict = reduce(dict.get, key[:-1], my_dict)
my_dict[key[-1]] = value
def del_key(my_dict, key):
key = key.split(".")
my_dict = reduce(dict.get, key[:-1], my_dict)
del my_dict[key[-1]]
Ответ 2
Вы можете это иметь. Вы можете подклассифицировать dict, добавить ключевой поиск (и даже сохранить имя dict), используя код, аналогичный приведенному ниже. Форма {...}
, тем не менее, по-прежнему будет использовать встроенный класс dict (теперь называемый orig_dict), поэтому вы должны заключить его так: Dict({...})
. Эта реализация рекурсивно преобразует словари в новую форму, поэтому вам не нужно использовать вышеописанный метод для любых словарных статей, которые являются просто словарями.
orig_dict = dict
class Dict(orig_dict):
def __init__(self, *args, **kwargs):
super(Dict, self).__init__(*args, **kwargs)
for k, v in self.iteritems():
if type(v) == orig_dict and not isinstance(v, Dict):
super(Dict, self).__setitem__(k, Dict(v))
def __getattribute__(self, k):
try: return super(Dict, self).__getattribute__(k)
except: return self.__getitem__(k)
def __setattr__(self, k, v):
if self.has_key(k): self.__setitem__(k, v)
else: return super(Dict, self).__setattr__(k, v)
def __delattr__(self, k):
try: self.__delitem__(k)
except: super(Dict, self).__delattr__(k)
def __setitem__(self, k, v):
toconvert = type(v) == orig_dict and not isinstance(v, Dict)
super(Dict, self).__setitem__(k, Dict(v) if toconvert else v)
# dict = Dict <-- you can even do this but I advise against it
# testing:
b = Dict(a=1, b=Dict(c=2, d=3))
c = Dict({'a': 1, 'b': {'c': 2, 'd': 3}})
d = Dict(a=1, b={'c': 2, 'd': {'e': 3, 'f': {'g': 4}}})
b.a = b.b
b.b = 1
d.b.d.f.g = 40
del d.b.d.e
d.b.c += d.b.d.f.g
c.b.c += c.a
del c.a
print b
print c
print d
Ответ 3
Рекурсия все еще работает.
def walk_into( dict, key ):
head, _, tail = key.partition('.')
if tail:
return walk_into( dict[head], tail )
return dict, key
d, k = walk_into( my_dict, "root.secondary.user2" )
d[k]
может использоваться для получения или ввода нового значения.