Я нахожу его более удобным для Dict доступа клавиш , как obj.foo
вместо того , чтобы obj['foo']
, таким образом , я написал этот фрагмент кода:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
Тем не менее, я предполагаю, что должна быть какая-то причина, по которой Python не предоставляет эту функциональность из коробки. Каковы будут предостережения и недостатки доступа к ключам диктовки таким образом?
python
dictionary
syntax
attributes
Изз ад-Дин Рухулессин
источник
источник
collections.namedtuple
очень полезно для этого.easydict.EasyDict
Ответы:
Лучший способ сделать это:
Некоторые плюсы:
.keys()
работает нормально. Если, конечно, вы не назначите им какое-либо значение, см. Ниже)AttributeError
вместоKeyError
Минусы:
.keys()
будут работать просто отлично, если они перезаписываются входящими даннымиE1123(unexpected-keyword-arg)
иE1103(maybe-no-member)
Краткое объяснение того, как это работает
__dict__
.__dict__
был «простым диктом», поэтому мы можем назначить любой подклассdict()
внутреннего словаря.AttrDict()
экземпляр, который создаем (как есть__init__
).super()
«s__init__()
метода , мы убедились , что он (уже) ведет себя так же , как словарь, так как эта функция требует всей словарь конкретизации код.Одна из причин, почему Python не предоставляет эту функциональность из коробки
Как отмечено в списке «против», это объединяет пространство имен хранимых ключей (которые могут быть получены из произвольных и / или ненадежных данных!) С пространством имен встроенных атрибутов метода dict. Например:
источник
.
, вы не можете нарушать правила языка :) И я не хотелAttrDict
бы автоматически преобразовывать содержащие пространство поля во что-то другое.Вы можете использовать все допустимые строковые символы как часть ключа, если используете обозначение массива. Например,
obj['!#$%^&*()_']
источник
What would be the caveats and pitfalls of accessing dict keys in this manner?
(в качестве атрибутов), и ответ в том, что большинство символов, показанных здесь, не будут использоваться.Из этого другого SO вопроса есть отличный пример реализации, который упрощает ваш существующий код. Как насчет:
Гораздо более лаконичен и не оставляет места для лишних хлопот, попадающих в вашу жизнь
__getattr__
и__setattr__
функционирующих в будущем.источник
d = AttributeDict(foo=1)
.d.bar = 1
атрибут bar хранится внутри атрибута dict, но не в самом dict. печатьd
показывает только элемент foo.d = AttributeDict(foo=1);d.bar = 1;print d
=> У{'foo': 1, 'bar': 1}
меня работает!__getattr__
метод, который вызывает,AttributeError
если данный атрибут не существует, в противном случае такие вещи, какgetattr(obj, attr, default_value)
не работают (т.е. не возвращаются,default_value
еслиattr
не существуетobj
)В котором я отвечаю на вопрос, который был задан
Почему Python не предлагает это из коробки?
Я подозреваю, что это связано с дзен Python : «Должен быть один - и желательно только один - очевидный способ сделать это». Это создаст два очевидных способа доступа к значениям из словарей:
obj['key']
иobj.key
.Предостережения и подводные камни
К ним относятся возможное отсутствие ясности и путаницы в коде. то есть, следующее может ввести в заблуждение кого- то, кто собирается поддержать ваш код на более позднем этапе, или даже вас, если вы не вернетесь к нему на некоторое время. Опять же, из дзен : «Читаемость имеет значение!»
Если
d
создается экземпляр илиKEY
определяется илиd[KEY]
назначается далеко от того места, гдеd.spam
он используется, это может легко привести к путанице в отношении того, что делается, поскольку это не часто используемая идиома. Я знаю, что это может сбить меня с толку.Кроме того, если вы измените значение
KEY
следующим образом (но пропустите изменениеd.spam
), вы получите:ИМО, не стоит усилий.
Другие предметы
Как уже отмечали другие, вы можете использовать любой хешируемый объект (не просто строку) в качестве ключа. Например,
законно, но
не является. Это дает вам доступ ко всему диапазону печатных символов или других хешируемых объектов для ключей словаря, которых у вас нет при доступе к атрибуту объекта. Это делает возможной такую магию, как метакласс кэшированных объектов, например рецепт из Кулинарной книги Python (гл. 9) .
В котором я редактирую
Я предпочитаю эстетику
spam.eggs
болееspam['eggs']
(я думаю, она выглядит чище), и я действительно начал жаждать эту функциональность, когда я встретилnamedtuple
. Но удобство в том, чтобы сделать следующее, превосходит это.Это простой пример, но я часто нахожу себя использующим диктовки в других ситуациях, чем я использую
obj.key
нотацию (то есть, когда мне нужно прочитать префы в файле XML). В других случаях, когда я испытываю желание создать экземпляр динамического класса и присвоить ему некоторые атрибуты по эстетическим соображениям, я продолжаю использовать dict для согласованности, чтобы улучшить читаемость.Я уверен, что ОП давно решил эту проблему к своему удовлетворению, но если он все еще хочет эту функциональность, тогда я предлагаю ему загрузить один из пакетов из pypi, который предоставляет его:
Куча , с которой я больше знаком. Подклассdict
, так что у вас есть все, что функциональность.AttrDict также выглядит довольно неплохо, но я не настолько знаком с ним и не изучил источник так подробно, как Bunch .Однако, чтобы улучшить читабельность его кода, я настоятельно рекомендую не смешивать его стили обозначений. Если он предпочитает эту запись, он должен просто создать экземпляр динамического объекта, добавить к нему нужные атрибуты и назвать его днем:
В котором я уточняю, чтобы ответить на дополнительный вопрос в комментариях
В комментариях (ниже) Элмо спрашивает:
Хотя я никогда не использовал этот вариант использования (опять же, я склонен использовать вложенный
dict
, для согласованности), работает следующий код:источник
Предостережение: по некоторым причинам такие классы, кажется, нарушают многопроцессорный пакет. Я только что некоторое время боролся с этой ошибкой, прежде чем нашел это SO: Нахождение исключения в многопроцессорной среде Python
источник
Вы можете извлечь удобный контейнерный класс из стандартной библиотеки:
чтобы избежать необходимости копировать вокруг битов кода. Нет стандартного доступа к словарю, но легко получить его обратно, если вы действительно этого хотите. Код в argparse прост,
источник
types.SimpleNamespace
docs.python.org/dev/library/types.html#types.SimpleNamespaceЧто делать, если вы хотите ключ, который был методом, например,
__eq__
или__getattr__
?И вы не сможете получить запись, которая не начинается с буквы, так что использование
0343853
в качестве ключа отключено.А что, если вы не хотите использовать строку?
источник
pickle.dump
использует__getstate__
кортежи могут быть использованы ключи dict. Как бы вы получили доступ к кортежу в вашей конструкции?
Кроме того, namedtuple - это удобная структура, которая может предоставлять значения через атрибут доступа.
источник
Как насчет Prodict , маленького класса Python, который я написал, чтобы управлять ими всеми :)
Кроме того, вы получаете автоматическое завершение кода , рекурсивные реализации объектов и автоматическое преобразование типов !
Вы можете сделать именно то, что вы просили:
Пример 1: Тип подсказки
Пример 2: автоматическое преобразование типов
источник
Это не работает в целом. Не все действительные ключи dict создают адресуемые атрибуты («ключ»). Итак, вам нужно быть осторожным.
Все объекты Python в основном являются словарями. Поэтому я сомневаюсь, что есть много производительности или другого штрафа.
источник
Это не относится к первоначальному вопросу, но должно быть полезно для людей, которые, как и я, попадают сюда при поиске библиотеки, которая предоставляет эту функциональность.
Наркоман для этого очень полезен: https://github.com/mewwts/addict, он заботится о многих проблемах, упомянутых в предыдущих ответах.
Пример из документов:
С наркоманом:
источник
Мне стало интересно, каково текущее состояние «dict keys as attr» в экосистеме python. Как отметили несколько комментаторов, это, вероятно, не то, что вы хотите сделать своими руками с нуля , так как есть несколько ловушек и ружей, некоторые из которых очень тонкие. Кроме того, я бы не рекомендовал использовать его
Namespace
в качестве базового класса, я был на этом пути, это не красиво.К счастью, есть несколько пакетов с открытым исходным кодом, предоставляющих эту функциональность, готовых к установке pip! К сожалению, есть несколько пакетов. Вот краткий обзор по состоянию на декабрь 2019 года.
Претенденты (последний коммит в мастере | #commits | #contribs | охват%):
Больше не поддерживается или недостаточно поддерживается:
В настоящее время я рекомендую жевать или наркоман . У них есть большинство коммитов, участников и релизов, предлагающих здоровую базу кода с открытым исходным кодом для каждого. Они имеют самый чистый вид readme.md, 100% охват и красивый набор тестов.
У меня нет собаки в этой гонке (пока!), Кроме того, что я бросил свой собственный код dict / attr и потратил кучу времени, потому что я не знал обо всех этих вариантах :). Я могу внести свой вклад в наркоманию / жаворонок в будущем, так как я предпочел бы увидеть один солидный пакет, а не набор фрагментированных Если они вам нравятся, помогите! В частности, похоже, что munch может использовать значок codecov, а наркоман может использовать значок версии python.
наркоманы плюсы:
наркоманы минусы:
typing.Dict
если выfrom addict import Dict
Мунк плюсы:
жевать минусы:
В котором я редактирую
Много месяцев назад, когда я использовал текстовые редакторы для написания Python, в проектах, где только я или один другой разработчик, мне нравился стиль dict-attrs, возможность вставлять ключи, просто объявив
foo.bar.spam = eggs
. Сейчас я работаю над командами и использую IDE для всего, и я отошел от подобных структур данных и динамической типизации в целом в пользу статического анализа, функциональных методов и подсказок типов. Я начал экспериментировать с этой техникой, подклассифицируя Pstruct с объектами моего собственного дизайна:Это дает вам объект, который все еще ведет себя как диктованный, но также позволяет вам получить доступ к ключам, таким как атрибуты, гораздо более жестким способом. Преимущество здесь в том, что я (или несчастные потребители вашего кода) точно знаю, какие поля могут и не могут существовать, а IDE может автоматически заполнять поля. Также подклассификация vanilla
dict
означает, что сериализация JSON проста. Я думаю, что следующей эволюцией в этой идее будет создание собственного генератора protobuf, который испускает эти интерфейсы, и приятным дополнением является то, что вы получаете межязыковые структуры данных и IPC через gRPC практически бесплатно.Если вы решите использовать атрибуты, важно задокументировать, какие поля ожидаются, для вашего собственного (и вашего товарища по команде) здравомыслия.
Не стесняйтесь редактировать / обновлять этот пост, чтобы держать его в курсе
источник
addict
том, что он не будет вызывать исключения, когда вы неправильно пишете атрибут, так как он возвращает новыйDict
(это необходимо для работы foo.abc = 'bar').Вот краткий пример неизменяемых записей с использованием встроенного
collections.namedtuple
:и пример использования:
источник
Просто чтобы добавить разнообразие в ответ, Sci-Kit Learn реализовал это следующим образом
Bunch
:Все , что вам нужно , это получить
setattr
иgetattr
методы - теgetattr
проверки для ключей Dict и движется к проверке фактических атрибутов.setstaet
Является исправлением для исправления для засолки / unpickling «сгустков» - если inerested проверки https://github.com/scikit-learn/scikit-learn/issues/6196источник
Не нужно писать свои собственные, так как setattr () и getattr () уже существуют.
Преимущество объектов класса, вероятно, вступает в игру в определении класса и наследовании.
источник
Я создал это на основе ввода из этой темы. Мне нужно использовать odict, поэтому мне пришлось переопределить get и установить attr. Я думаю, что это должно работать для большинства специальных целей.
Использование выглядит так:
Класс:
Это довольно крутой шаблон, уже упомянутый в потоке, но если вы просто хотите взять dict и преобразовать его в объект, который работает с автозаполнением в IDE, и т.д .:
источник
По-видимому, теперь есть библиотека для этого - https://pypi.python.org/pypi/attrdict - которая реализует эту точную функциональность плюс рекурсивное слияние и загрузка json. Может стоит посмотреть.
источник
Это то, что я использую
источник
namedtuple('Args', list(args.keys()))(**args)
Вы можете сделать это, используя этот класс, который я только что сделал. С этим классом вы можете использовать
Map
объект как другой словарь (включая сериализацию json) или с точечной нотацией. Я надеюсь помочь вам:Примеры использования:
источник
dict
методы, например:m=Map(); m["keys"] = 42; m.keys()
giveTypeError: 'int' object is not callable
.field/attribute
а не amethod
, но если вы назначите метод вместо числа, вы можете получить доступ к этому методуm.method()
.Позвольте мне опубликовать еще одну реализацию, которая основывается на ответе Kinvais, но объединяет идеи из AttributeDict, предложенные в http://databio.org/posts/python_AttributeDict.html .
Преимущество этой версии в том, что она также работает для вложенных словарей:
источник
источник
Решение:
источник
Как предполагает @Henry, одной из причин, по которым точечный доступ может не использоваться в dicts, является то, что он ограничивает имена ключей dict допустимыми переменными python, тем самым ограничивая все возможные имена.
Ниже приведены примеры того, почему точка доступа не будет полезна в общем случае, если таковые имеются
d
:Срок действия
Следующие атрибуты будут недействительными в Python:
Стиль
Соглашения PEP8 наложат мягкое ограничение на именование атрибутов:
A. Зарезервированные имена ключевых слов (или встроенных функций):
Б. Правило прецедента для методов и имен переменных :
Иногда эти проблемы возникают в таких библиотеках, как pandas , которые разрешают точечный доступ к столбцам DataFrame по имени. Механизмом по умолчанию для разрешения ограничений именования является также обозначение массива - строка в скобках.
Если эти ограничения не применяются к вашему варианту использования, есть несколько опций для структур данных с точечным доступом .
источник
Вы можете использовать dict_to_obj https://pypi.org/project/dict-to-obj/ Он делает именно то, что вы просили
источник
.idea
и любые пользовательские или сгенерированные IDE файлы в ваш.gitignore
.Это не «хороший» ответ, но я подумал, что это было изящно (он не обрабатывает вложенные символы в текущей форме). Просто оберните ваш диктант в функцию:
Теперь у вас немного другой синтаксис. Чтобы получить доступ к элементам dict как к атрибутам
f.key
. Чтобы получить доступ к элементам dict (и другим методам dict) обычным способом, сделайте,f()['key']
и мы можем удобно обновить dict, вызвав f с ключевыми словами и / или словаремпример
И вот оно. Я буду рад, если кто-нибудь предложит преимущества и недостатки этого метода.
источник
Как отметил Дуг, есть пакет Bunch, который вы можете использовать для достижения
obj.key
функциональности. На самом деле есть более новая версия под названиемNeoBunch
У него есть отличная возможность конвертировать ваш диктант в объект NeoBunch с помощью функции neobunchify . Я часто использую шаблоны Mako, и передача данных в виде объектов NeoBunch делает их гораздо более читабельными, поэтому, если вам случится так, что в вашей программе на Python вам пришлось использовать обычный dict, но вы хотите использовать точечную запись в шаблоне Mako, вы можете использовать ее следующим образом:
И шаблон Мако может выглядеть так:
источник
Самый простой способ - определить класс, назовем его Namespace. который использует объект dict .update () на dict. Тогда дикт будет рассматриваться как объект.
источник