TypeError: obiekt „dict_keys” nie obsługuje indeksowania


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]

Po uruchomieniu shufflefunkcji pojawia się następujący błąd, dlaczego tak jest?

TypeError: 'dict_keys' object does not support indexing

7
Wydaje się, że błąd python3
DataEngineer

Odpowiedzi:


231

Najwyraźniej przechodzisz d.keys()do swojej shufflefunkcji. Prawdopodobnie zostało to napisane za pomocą python2.x (po d.keys()zwróceniu listy). W python3.x d.keys()zwraca dict_keysobiekt, który zachowuje się bardziej jak a setniż a list. W związku z tym nie może być indeksowany.

Rozwiązaniem jest przejście list(d.keys())(lub po prostu list(d)) do shuffle.


22
. . . Lub po prostu, list(d)który da ci listę kluczy zarówno w python2.x, jak i python3.x bez robienia żadnych kopii :-)
mgilson

11
To dziwna, przełomowa decyzja dotycząca projektu zmiany dla pythona3.
Jason

9
Możesz tak pomyśleć, ale zdecydowanie uważam, że to była dobra decyzja. dict_keysObiekt zachowuje się o wiele więcej jak tylko klucze połowie dict. W szczególności obsługują testowanie członkostwa O (1) (i inne metody podobne do zestawu, które można skutecznie wdrożyć poza tym faktem). Te rzeczy nie są możliwe w przypadku listy, a jeśli chcesz mieć listę kluczy dyktowania, zawsze możesz po prostu to zrobić list(your_dictionary).
mgilson

jest to pomocne dla mnie, gdy widzę, że python3 wymaga od nas zawinięcia słownika listą.
DataEngineer

2
@Crt - shuffleto nazwa funkcji w kodzie oryginalnego nadawcy (funkcja, która zgłasza błąd). Patrząc na kod, myślę, że został skopiowany / wklejony z random.shuffleimplementacji w bibliotece standardowej :-)
mgilson

11

Przekazujesz wynik somedict.keys()funkcji. W Pythonie 3 dict.keysnie zwraca listy, ale obiekt podobny do zestawu, który reprezentuje widok kluczy słownika i (będąc podobnym do zestawu) nie obsługuje indeksowania.

Aby rozwiązać problem, użyj list(somedict.keys())do zbierania kluczy i pracuj z tym.


10

Konwersja iterowalnej na listę może mieć koszt. Zamiast tego, aby zdobyć pierwszy przedmiot, możesz użyć:

next(iter(keys))

Lub, jeśli chcesz iterować po wszystkich elementach, możesz użyć:

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

1

Dlaczego musisz wdrożyć shuffle, skoro już istnieje? Pozostań na ramionach gigantów.

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)

Odpowiedź dotyczy wiedzy ogólnej, ale nie odnosi się do tego, o co pytał PO.
JC Rocamonde

Masz rację. Wygląda na to, że chce zaimplementować swój własny randomizer.
FooBar167

1
psah, może tak naprawdę nie wiedział, że mógłby użyć wbudowanej, ale pytanie wydaje się dotyczyć błędu typu. Mimo to mam nadzieję, że zmienił i wykorzystał twoją opcję (chyba że jest to coś bardzo konkretnego), aby przestrzegać podstawowych zasad DRY i ekonomii kodu.
JC Rocamonde

1

W Pythonie 2 dict.keys () zwraca listę, podczas gdy w Pythonie 3 zwraca generator.

Możesz tylko iterować po wartościach, w przeciwnym razie będziesz musiał jawnie przekonwertować je na listę, tj. Przekazać do funkcji listy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.