Доступ до елемента dict_keys за індексом у Python3


131

Я намагаюся отримати доступ до елемента dict_key за його індексом:

test = {'foo': 'bar', 'hello': 'world'}
keys = test.keys()  # dict_keys object

keys.index(0)
AttributeError: 'dict_keys' object has no attribute 'index'

Я хочу отримати foo.

те саме:

keys[0]
TypeError: 'dict_keys' object does not support indexing

Як я можу це зробити?


9
У py3.x dict.keys()повертає такий набір об'єкта перегляду, як не список (тому індексація неможлива). Використанняkeys = list(test)
Ashwini Chaudhary

коли я роблю список (something_dict), порядок кортежу є випадковим: приклад: list ({'foo': 'bar', 'hello': 'world'}) може повертати: list (foo, hello) або list (привіт, foo), чому це випадково?
fj123x

7
Дикти не мають жодного замовлення . (Використовуйте, collections.OrderedDictякщо ви хочете замовити ключі)
Ashwini Chaudhary

Цікава дискусія про безпеку ниток тут, що перераховує різні підходи до вирішення цієї проблеми: blog.labix.org/2008/06/27/…
Павло

Відповіді:


161

Зателефонуйте list()до словника:

keys = list(test)

У Python 3 dict.keys()метод повертає об’єкт подання словника , який виступає як набір. Ітерація над словником також дає клавіші, тому перетворення словника в список призводить до переліку всіх клавіш:

>>> test = {'foo': 'bar', 'hello': 'world'}
>>> list(test)
['foo', 'hello']
>>> list(test)[0]
'foo'

3
Слідкуйте за списком (dict.keys ()) в Python 3 - Labix Blog чітко пояснює, у чому полягає проблема, не пропонуючи рішення. Це чудово!
Брендон Бредлі

@BrandonBradley: загалом кажучи: покладатися на певні дії, які є атомними, все одно погана ідея, оскільки Python настільки сильно динамічний. Ваш код легко передається dictпідкласу, наприклад, де .keys()він обробляється в коді Python (наприклад, може відбуватися комутаційний потік).
Martijn Pieters

@BrandonBradley: дякую за посилання. У Python3 для мене працює лише одне з коментарів до цього блогу: сортування (dict.keys ()). У Python2 dict.keys () поверне список ключових значень.
Добрий Воля

2
@GoodWill: sorted(dict)зробив би точно так само; створити список ключів у відсортованому порядку. list(dict)надасть вам список у словниковому порядку.
Martijn Pieters

1
або користуватисяkeys = [*test]
Alex78191

59

Не повна відповідь, але, можливо, корисна підказка. Якщо це дійсно перший предмет, який ви хочете *, то

next(iter(q))

набагато швидше, ніж

list(q)[0]

для великих диктів, оскільки вся справа не повинна зберігатися в пам'яті.

Для 10 000 000 предметів я виявив, що це майже в 40 000 разів швидше.

* Перший елемент у випадку, якщо дикт є лише псевдовипадковим елементом перед Python 3.6 (після цього він впорядкований у стандартній реалізації, хоча на нього не рекомендується покладатися).


5
Це завжди було однією з моїх найбільших проблем, коли все стало ітераторами в Py3. Це, безумовно, ефективніше, але так багато випадків використання стають "нечистими" та складними без жодної причини. Наприклад, чому вони не можуть просто підтримувати індексацію на ітераторі, не обов'язково втрачаючи продуктивність?
Ehsan Kia

2

Я хотів пари "ключ" та "значення" першого елемента словника. Я використав наступний код.

 key, val = next(iter(my_dict.items()))

0
test = {'foo': 'bar', 'hello': 'world'}
ls = []
for key in test.keys():
    ls.append(key)
print(ls[0])

Звичайний спосіб додавання ключів до статично визначеного списку, а потім їх індексація для того ж


2
Це не помиляється, але чому б і ні ls = list(test.keys())? Я вважаю це більш простим.
Валентино

Так, це більш ефективно. Я написав це лише для того, щоб показати читабельність.
Pranav ду

0

У багатьох випадках це може бути проблема XY . Чому ви індексуєте свої ключові слова за позицією? Вам справді потрібно? Донедавна словники навіть не впорядковувалися в Python, тому доступ до першого елемента був довільним.

Я щойно переклав якийсь код Python 2 на Python 3:

keys = d.keys()
for (i, res) in enumerate(some_list):
    k = keys[i]
    # ...

що не дуже, але теж не дуже погано. Спочатку я збирався замінити його жахливим

    k = next(itertools.islice(iter(keys), i, None))

перш ніж я зрозумів, що це все набагато краще написано як

for (k, res) in zip(d.keys(), some_list):

що працює чудово.

Я вважаю, що в багатьох інших випадках можна уникнути індексації словникових ключів за позицією. Хоча словники упорядковані в Python 3.7, покладатися на це не дуже. Код вище працює лише тому, що вміст some_listнещодавно був створений зі вмісту d.

Уважно подивіться на свій код, якщо вам дійсно потрібно отримати доступ до disk_keysелемента за індексом. Можливо, не потрібно.


0

Спробуйте це

keys = [next(iter(x.keys())) for x in test]
print(list(keys))

Результат виглядає приблизно так. ['foo', 'привіт']

Ви можете знайти більше можливих рішень тут .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.