, где я отвечаю на вопрос, который был задан
Почему Python не предлагает его из коробки?
Я подозреваю, что это имеет отношение к Zen of Python : «Должен быть один - и желательно только один - очевидный способ сделать это». Это создаст два очевидных способа доступа к значениям из словарей: obj['key']
и obj.key
.
Предостережения и ловушки
К ним относятся возможное отсутствие ясности и путаницы в коде. то есть, следующее может сбить с толку кого-то еще , который собирается поддержать ваш код позднее или даже вас, если вы не собираетесь возвращаться к нему некоторое время. Снова из Zen : «Читаемость имеет значение!»
>>> KEY = 'spam'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Если создается экземпляр d
или KEY
определяется или d[KEY]
назначается далеко от места использования d.spam
, это может легко привести к путанице о том, что делается, так как это не часто используемая идиома. Я знаю, что это может сбить меня с толку.
В дополнение, если вы измените значение KEY
следующим образом (но пропустите изменение d.spam
), вы получите:
>>> KEY = 'foo'
>>> d[KEY] = 1
>>> # Several lines of miscellaneous code here...
... assert d.spam == 1
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: 'C' object has no attribute 'spam'
ИМО, не стоит усилий.
Другие предметы
Как уже отмечали другие, вы можете использовать любой хешируемый объект (не просто строку) в качестве ключа dict. Например,
>>> d = {(2, 3): True,}
>>> assert d[(2, 3)] is True
>>>
законно, но
>>> C = type('C', (object,), {(2, 3): True})
>>> d = C()
>>> assert d.(2, 3) is True
File "<stdin>", line 1
d.(2, 3)
^
SyntaxError: invalid syntax
>>> getattr(d, (2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: getattr(): attribute name must be string
>>>
нет. Это дает вам доступ ко всему диапазону печатаемых символов или других хешируемых объектов для ключей словаря, которых у вас нет при доступе к атрибуту объекта. Это делает возможным такое волшебство, как метакласс кэшированных объектов, например, рецепт из Python Cookbook (Ch. 9) .
Где я редактирую
Я предпочитаю эстетику spam.eggs
, а не spam['eggs']
(я думаю, что она выглядит чище), и я действительно начал жаждать этой функциональности, когда встретил namedtuple
. Но удобство в том, чтобы делать следующее, превосходит это.
>>> KEYS = 'spam eggs ham'
>>> VALS = [1, 2, 3]
>>> d = {k: v for k, v in zip(KEYS.split(' '), VALS)}
>>> assert d == {'spam': 1, 'eggs': 2, 'ham': 3}
>>>
Это простой пример, но я часто использую диктовки в других ситуациях, чем я использую нотацию obj.key
(то есть, когда мне нужно прочитать префы в файле XML). В других случаях, когда я испытываю желание создать экземпляр динамического класса и присвоить ему некоторые атрибуты по эстетическим соображениям, я продолжаю использовать dict для согласованности, чтобы улучшить читаемость.
Я уверен, что ОП давно решил эту проблему к своему удовлетворению, но если он все еще хочет эту функциональность, тогда я предлагаю ему загрузить один из пакетов из pypi, который предоставляет его:
- Связка - это тот, с которым я больше знаком. Подкласс
dict
, так что у вас есть все эти функции.
- AttrDict также выглядит так, как будто это также довольно хорошо, но я не настолько знаком с ним и не просмотрел источник так подробно, как у меня Bunch .
- Как отмечается в комментариях Ротарети, Bunch устарел, но есть активный форк, называемый Munch .
Однако, чтобы улучшить читабельность его кода, я настоятельно рекомендую ему , а не смешивать его стили обозначений. Если он предпочитает эту запись, он должен просто создать экземпляр динамического объекта, добавить к нему нужные атрибуты и назвать его днем:
>>> C = type('C', (object,), {})
>>> d = C()
>>> d.spam = 1
>>> d.eggs = 2
>>> d.ham = 3
>>> assert d.__dict__ == {'spam': 1, 'eggs': 2, 'ham': 3}
<ч />
В котором я обновляюсь, чтобы ответить на дополнительный вопрос в комментариях
В комментариях (ниже) Elmo спрашивает:
Что, если вы хотите пойти еще глубже? (имеется в виду тип (...))
Хотя я никогда не использовал этот вариант использования (опять же, я склонен использовать вложенный dict
, для
согласованность), работает следующий код:
>>> C = type('C', (object,), {})
>>> d = C()
>>> for x in 'spam eggs ham'.split():
... setattr(d, x, C())
... i = 1
... for y in 'one two three'.split():
... setattr(getattr(d, x), y, i)
... i += 1
...
>>> assert d.spam.__dict__ == {'one': 1, 'two': 2, 'three': 3}