Как использовать точку "." получить доступ к членам словаря? - PullRequest
205 голосов
/ 28 февраля 2010

Как сделать элементы словаря Python доступными через точку "."?

Например, вместо того, чтобы писать mydict['val'], я бы хотел написать mydict.val.

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

mydict.mydict2.val 

будет означать

mydict = { 'mydict2': { 'val': ... } }

Ответы [ 20 ]

187 голосов
/ 16 мая 2014

Я всегда держал это в файле утилит. Вы также можете использовать его как миксин на своих классах.

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'
116 голосов
/ 20 августа 2015

Вы можете сделать это, используя этот класс, который я только что создал. С этим классом вы можете использовать объект Map как другой словарь (включая сериализацию json) или с точечной нотацией. Я надеюсь помочь вам:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

Примеры использования:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']
92 голосов
/ 11 февраля 2015

Установить dotmap через pip

pip install dotmap

Он делает все, что вы хотите, и подклассы dict, поэтому он работает как обычный словарь:

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'

Кроме того, вы можете преобразовать его в dict объекты:

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

Это означает, что если что-то, к чему вы хотите получить доступ, уже находится в форме dict, вы можете превратить его в DotMap для быстрого доступа:

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

Наконец, он автоматически создает новые дочерние DotMap экземпляры, чтобы вы могли делать такие вещи:

m = DotMap()
m.people.steve.age = 31

Сравнение с кучей

Полное раскрытие: я создатель DotMap . Я создал его, потому что Bunch эти функции отсутствовали

  • запоминание элементов заказа и повторение в этом порядке
  • автоматическое создание потомков DotMap, которое экономит время и делает код чище, когда у вас много иерархии
  • построение из dict и рекурсивное преобразование всех дочерних dict экземпляров в DotMap
56 голосов
/ 28 февраля 2010

Получите из dict и внедрите __getattr__ и __setattr__.

Или вы можете использовать Bunch , который очень похож.

Я не думаю, что возможно создать встроенный класс dict для monkeypatch.

18 голосов
/ 09 февраля 2012

Я пробовал это:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]

Вы можете попробовать __getattribute__ тоже.

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

15 голосов
/ 22 декабря 2016

Fabric имеет действительно хорошую, минимальную реализацию . Расширяя это, чтобы разрешить вложенный доступ, мы можем использовать defaultdict, и результат будет выглядеть примерно так:

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

    def __setattr__(self, key, value):
        self[key] = value

Используйте его следующим образом:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

Это немного конкретизирует ответ Кугеля на «Получите из диктов и внедрите __getattr__ и __setattr__». Теперь вы знаете как!

8 голосов
/ 01 мая 2016

Если вы хотите выбрать измененный словарь, вам нужно добавить несколько методов состояния к ответам выше:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self
7 голосов
/ 28 февраля 2010

Не. Доступ к атрибутам и индексация - это разные вещи в Python, и вы не должны хотеть, чтобы они выполняли то же самое. Создайте класс (возможно, созданный namedtuple), если у вас есть что-то, что должно иметь доступные атрибуты, и используйте нотацию [], чтобы получить предмет из диктанта.

6 голосов
/ 30 августа 2012

Опираясь на ответ Кугеля и принимая во внимание слова предостережения Майка Грэма, что если мы сделаем обертку?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setattr__(self, name, value):
    self._data[name] = value  

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other
5 голосов
/ 05 ноября 2017

Мне нравится Munch , и он предоставляет множество удобных опций поверх точечного доступа.

импортный мунк

temp_1 = {'person': {'fname': 'senthil', 'lname': 'ramalingam'}}

dict_munch = munch.munchify (temp_1)

dict_munch.person.fname

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