Доступ к ключам диктовки как к атрибуту? - PullRequest
252 голосов
/ 13 февраля 2011

Я нахожу более удобным доступ к ключам dict как obj.foo вместо obj['foo'], поэтому я написал следующий фрагмент:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

Однако я предполагаю, что должна быть какая-то причина, по которой Python не 'Предоставить эту функциональность из коробки.Каковы будут предостережения и недостатки доступа к ключам диктовки таким образом?

Ответы [ 24 ]

1 голос
/ 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!'
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']
0 голосов
/ 04 сентября 2018

Какими были бы предостережения и ловушки при доступе к ключам диктовки таким образом?

Как предполагает @Henry, одна из причин, по которым точка-доступ не может использоваться в dicts, заключается в том, что он ограничивает имена ключей dict допустимыми переменными python, тем самым ограничивая все возможные имена.

Ниже приведены примеры того, почему пунктирный доступ не будет полезен в общем случае, если даётся, d:

Действительность

Следующие атрибуты будут недействительными в Python:

d.1_foo                           # enumerated names
d./bar                            # path names
d.21.7, d.12:30                   # decimals, time
d.""                              # empty strings
d.john doe, d.denny's             # spaces, misc punctuation 
d.3 * x                           # expressions  

Style

Соглашения PEP8 наложат мягкое ограничение на присвоение имен атрибутам:

A. Зарезервированные ключевые слова (или встроенная функция) имена:

d.in
d.False, d.True
d.max, d.min
d.sum
d.id

Если имя аргумента функции конфликтует с зарезервированным ключевым словом, обычно лучше добавить одно завершающее подчеркивание ...

B. Правило регистра для методов и имен переменных :

Имена переменных соответствуют тому же соглашению, что и имена функций.

d.Firstname
d.Country

При необходимости используйте правила именования функций: строчные буквы со словами, разделенными подчеркиванием, для улучшения читаемости.


Иногда эти проблемы поднимаются в библиотеках, таких как pandas , которые разрешают точечный доступ к столбцам DataFrame по имени. Механизмом по умолчанию для разрешения ограничений именования является также обозначение массива - строка в скобках.

Если эти ограничения не применяются к вашему варианту использования, есть несколько вариантов структур данных с точечным доступом .

0 голосов
/ 30 июня 2019

Вы можете использовать dict_to_obj https://pypi.org/project/dict-to-obj/ Это именно то, что вы просили

From dict_to_obj import DictToObj
a = {
'foo': True
}
b = DictToObj(a)
b.foo
True

0 голосов
/ 01 марта 2015

Это не «хороший» ответ, но я подумал, что это было изящно (он не обрабатывает вложенные запросы в текущей форме).Просто оберните ваш dict в функцию:

def make_funcdict(d={}, **kwargs)
    def funcdict(d={}, **kwargs):
        funcdict.__dict__.update(d)
        funcdict.__dict__.update(kwargs)
        return funcdict.__dict__
    funcdict(d, **kwargs)
    return funcdict

Теперь у вас немного другой синтаксис.Для доступа к элементам dict как атрибутам выполните f.key.Чтобы получить доступ к элементам dict (и другим методам dict) обычным способом, выполните f()['key'], и мы можем легко обновить dict, вызвав f с ключевыми словами и / или словарем

Пример

d = {'name':'Henry', 'age':31}
d = make_funcdict(d)
>>> for key in d():
...     print key
... 
age
name
>>> print d.name
... Henry
>>> print d.age
... 31
>>> d({'Height':'5-11'}, Job='Carpenter')
... {'age': 31, 'name': 'Henry', 'Job': 'Carpenter', 'Height': '5-11'}

И вот оно.Я буду рад, если кто-нибудь предложит преимущества и недостатки этого метода.

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