Доступ к python dict с помощью нескольких ключей поиска строки - PullRequest
13 голосов
/ 17 февраля 2012

Я пытаюсь создать простой механизм «поиска» в python и хотел убедиться, что в обширных библиотеках в python где-то уже что-то спрятано, но это еще не сделано, прежде чем создавать.

Я хочу взять диктовку, отформатированную примерно так

my_dict = { 
  "root": { 
    "secondary": { 
      "user1": { 
          "name": "jim", 
          "age": 24 
      }, 
      "user2": { 
        "name": "fred", 
        "age": 25 
      } 
    } 
  } 
}

и я пытаюсь получить доступ к данным, используя десятичную запись, которая будет похожа на

root.secondary.user2

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

Ответы [ 3 ]

28 голосов
/ 17 февраля 2012

Для этой цели в стандартной библиотеке нет ничего, но это довольно просто написать самостоятельно:

>>> 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 голосов
/ 17 февраля 2012

Вы можете иметь это. Вы можете создать подкласс 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
1 голос
/ 17 февраля 2012

Рекурсия все еще работает.

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] может использоваться для получения или установки нового значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...