TypeError: объект dict_keys не поддерживает индексирование

144
def shuffle(self, x, random=None, int=int):
    """x, random=random.random -> shuffle list x in place; return None.

    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """

    randbelow = self._randbelow
    for i in reversed(range(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = randbelow(i+1) if random is None else int(random() * (i+1))
        x[i], x[j] = x[j], x[i]

Когда я запускаю shuffleфункцию, возникает следующая ошибка, почему?

TypeError: 'dict_keys' object does not support indexing
gate_007
источник
7
кажется, ошибка
Python3

Ответы:

231

Очевидно, вы переходите d.keys()к своей shuffleфункции. Вероятно, это было написано с python2.x (когда d.keys()возвращали список). С python3.x d.keys()возвращает dict_keysобъект, который ведет себя намного больше, setчем a list. Как таковой, он не может быть проиндексирован.

Решение состоит в том, чтобы перейти list(d.keys())(или просто list(d)) к shuffle.

mgilson
источник
22
, , , Или просто, list(d)который даст вам список ключей на python2.x и python3.x без создания копий :-)
mgilson
11
Это странное решение по изменению дизайна Python3.
Джейсон
9
Вы можете так думать, но я определенно думаю, что это было правильное решение. dict_keysОбъект ведет себя намного больше , как просто ключи половины Dict. В частности, они поддерживают тестирование членства O (1) (и другие методы, подобные множеству, которые могут быть эффективно реализованы в дополнение к этому факту). Эти вещи невозможны со списком, и если вы хотите получить список ключей dict, вы всегда можете просто сделать это, list(your_dictionary)чтобы получить его.
mgilson
это полезно для меня, чтобы увидеть, что python3 требует от нас заключить словарь в список.
DataEngineer
2
@Crt - shuffleэто имя функции в исходном коде автора (функция, которая выдает ошибку). Глядя на код, я думаю, что он был скопирован / вставлен из random.shuffleреализации в стандартной библиотеке :-)
mgilson
11

Вы передаете результат somedict.keys()функции. В Python 3 dict.keysне возвращает список, но подобный множеству объект, который представляет представление ключей словаря и (будучи подобным множеству), не поддерживает индексирование.

Чтобы решить проблему, используйте list(somedict.keys())для сбора ключей и работать с этим.

user4815162342
источник
10

Преобразование итерируемого в список может иметь стоимость. Вместо этого, чтобы получить первый элемент, вы можете использовать:

next(iter(keys))

Или, если вы хотите перебрать все элементы, вы можете использовать:

items = iter(keys)
while True:
    try:
        item = next(items)
    except StopIteration as e:
        pass # finish
Сахама
источник
1

Зачем вам нужно реализовывать shuffle, когда он уже существует? Оставайтесь на плечах гигантов.

import random

d1 = {0:'zero', 1:'one', 2:'two', 3:'three', 4:'four',
     5:'five', 6:'six', 7:'seven', 8:'eight', 9:'nine'}

keys = list(d1)
random.shuffle(keys)

d2 = {}
for key in keys: d2[key] = d1[key]

print(d1)
print(d2)
FooBar167
источник
Ответ имеет отношение к общим знаниям, но он не относится к тому, что спрашивал ОП.
JC
Ты прав. Кажется, он хочет реализовать свой собственный рандомизатор.
FooBar167
1
Пса, может быть, он на самом деле не знал, что он мог бы использовать встроенный, но вопрос на самом деле, кажется, об ошибке типа. Тем не менее, я надеюсь, что он переключился и использовал ваш вариант (если это не что-то очень конкретное), чтобы следовать основным принципам DRY и экономии кода.
JC
1

В Python 2 dict.keys () возвращает список, тогда как в Python 3 он возвращает генератор.

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

DeWil
источник