При цьому я відповідаю на поставлене запитання
Чому Python не пропонує його поза коробкою?
Я підозрюю, що це стосується дзен Python : "Має бути один - і бажано лише один - очевидний спосіб зробити це". Це створило б два очевидних способи доступу до значень із словників: obj['key']
іobj.key
.
Печери та підводні камені
Сюди входить можлива відсутність ясності та плутанини в коді. тобто, наступне може заплутати когось іншого, хто збирається підтримувати ваш код на більш пізній термін, або навіть для вас, якщо ви не збираєтеся знову його вносити. Знову з Дзен : "Читання рахується!"
>>> 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'
ІМО, не вартих зусиль.
Інші предмети
Як зазначали інші, ви можете використовувати будь-який хешируемый об’єкт (а не лише рядок) як ключ дикту. Наприклад,
>>> 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 (гл. 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). В інших випадках, коли я спокушаюсь створити динамічний клас і нанести на нього деякі атрибути з естетичних міркувань, я продовжую використовувати вислів для послідовності з метою підвищення читабельності.
Я впевнений, що ОП давно вирішив це на його задоволення, але якщо він все-таки хоче цю функціональність, то я пропоную йому завантажити один з пакетів з pypi, який це забезпечує:
Пучок - той, з ким я більше знайомий. Підкласdict
, тому у вас є весь цей функціонал.
AttrDict також виглядає, що це теж непогано, але я не так знайомий з ним і не переглянув джерело так детально, як у мене букет .
- Наркоманія активно підтримується і надає доступ, схожий на attr тощо.
- Як зазначається в коментарях Ротареті, Бунк був застарілим, але є активна вилка під назвою 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}
Під час чого я оновлюю, щоб відповісти на подальше запитання у коментарях
У коментарях (нижче) Елмо запитує:
Що робити, якщо ви хочете піти на одну глибшу? (стосується типу (...))
Хоча я ніколи не використовував цей випадок використання (знову ж, я схильний використовувати вкладений 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}
collections.namedtuple
дуже корисний для цього.