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

7
здається, помилка python3
DataEngineer

Відповіді:


231

Ясно, що ви переходите d.keys()до своєї shuffleфункції. Ймовірно, це було написано з python2.x (коли d.keys()повертався список). З python3.x d.keys()повертає dict_keysоб'єкт, який веде себе набагато більше, setніж a list. Як такий, він не може бути індексований.

Рішення - перейти list(d.keys())(або просто list(d)) до shuffle.


22
. . . Або просто, list(d)який надасть вам список ключів як python2.x, так і python3.x, не роблячи жодної копії :-)
mgilson

11
Це дивне рішення про зміну дизайну для python3.
Джейсон

9
Ви можете так подумати, але я точно вважаю, що це було правильне рішення. dict_keysОб'єкт поводиться набагато більше , як просто ключі половини Dict. Зокрема, вони підтримують тестування членства на О (1) (та інші методи, подібні до встановлених наборів, які можуть бути ефективно впроваджені поверх цього факту). Зі списком такі речі неможливі, і якщо вам потрібен список ключів дикту, ви завжди могли просто зробити list(your_dictionary)це.
mgilson

це корисно для мене, коли я бачу, що python3 вимагає, щоб ми переклали словник зі списком.
DataEngineer

2
@Crt - shuffleце назва функції в оригінальному коді плаката (функція, яка видає помилку). Дивлячись на код, я думаю, що він був скопійований / вставлений з random.shuffle's реалізації в стандартній бібліотеці :-)
mgilson

11

Ви передаєте результат somedict.keys()функції. У Python 3 dict.keysсписок не повертає, але об'єкт, подібний до набору, який представляє перегляд клавіш словника і (як схожий на набір) не підтримує індексацію.

Щоб вирішити проблему, використовуйте list(somedict.keys())для збору ключів і працюйте з цим.


10

Перетворення ітерабельного списку може мати витрати. Натомість, щоб отримати перший елемент, ви можете використовувати:

next(iter(keys))

Або, якщо ви хочете перебрати всі елементи, ви можете використовувати:

items = iter(keys)
while True:
    try:
        item = next(items)
    except StopIteration as e:
        pass # finish

1

Чому потрібно здійснити перетасування, коли воно вже існує? Залишайтеся на плечах гігантів.

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)

Відповідь є загальновідомою, але вона не стосується того, що просила ОП.
JC Rocamonde

Ти маєш рацію. Здається, він хоче реалізувати власний рандомізатор.
FooBar167

1
psah, можливо, він насправді не знав, що він може використовувати вбудований, але питання, власне, стосується помилки типу. І все-таки, я сподіваюся, що він перейшов і застосував ваш варіант (якщо це щось не дуже специфічне), щоб дотримуватися основних принципів DRY та кодової економії.
JC Rocamonde

1

У Python 2 dict.keys () повертає список, тоді як у Python 3 повертає генератор.

Ви можете лише повторити його значення, можливо, вам доведеться явно перетворити їх у список, тобто передати його до функції списку.

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