TypeError: l'oggetto 'dict_keys' non supporta l'indicizzazione


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]

Quando eseguo la shufflefunzione genera il seguente errore, perché?

TypeError: 'dict_keys' object does not support indexing

7
sembra essere un errore
python3

Risposte:


231

Chiaramente stai passando d.keys()alla tua shufflefunzione. Probabilmente questo è stato scritto con python2.x (quando è stato d.keys()restituito un elenco). Con python3.x, d.keys()restituisce un dict_keysoggetto che si comporta in modo molto più simile a a setdi a list. Pertanto, non può essere indicizzato.

La soluzione è passare list(d.keys())(o semplicemente list(d)) a shuffle.


22
. . . O semplicemente list(d)che ti darà un elenco di chiavi sia su python2.x che su python3.x senza fare copie :-)
mgilson,

11
Questa è una strana decisione di modifica del cambiamento per python3.
Jason,

9
Potresti pensarlo, ma penso che sia stata la decisione giusta. L' dict_keysoggetto si comporta in modo molto più simile alle chiavi di metà di un dict. In particolare, supportano il test di appartenenza O (1) (e altri metodi simili a set che possono essere implementati in modo efficiente oltre a questo fatto). Queste cose non sono possibili con un elenco e se vuoi un elenco delle chiavi del dict, sei sempre stato in grado di farlo semplicemente list(your_dictionary)per ottenerlo.
mgilson,

questo è utile per me per vedere che python3 ci richiede di avvolgere il dizionario con la lista.
Data Engineer

2
@Crt - shuffleè il nome della funzione nel codice del poster originale (la funzione che genera l'errore). Guardando il codice, penso che sia stato copiato / incollato dall'implementazione random.shufflenella libreria standard :-)
mgilson

11

Stai passando il risultato somedict.keys()alla funzione. In Python 3, dict.keysnon restituisce un elenco, ma un oggetto simile a un set che rappresenta una vista delle chiavi del dizionario e (essendo simile a un set) non supporta l'indicizzazione.

Per risolvere il problema, utilizzare list(somedict.keys())per raccogliere le chiavi e lavorare con quello.


10

Convertire un iterabile in un elenco può avere un costo. Invece, per ottenere il primo oggetto, puoi usare:

next(iter(keys))

Oppure, se desideri scorrere tutti gli elementi, puoi utilizzare:

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

1

Perché è necessario implementare lo shuffle quando esiste già? Resta sulle spalle dei giganti.

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)

La risposta è rilevante per le conoscenze generali, ma non si rivolge a ciò che l'OP stava chiedendo.
JC Rocamonde,

Hai ragione. Sembra che voglia implementare il suo randomizzatore.
FooBar167,

1
psah, forse non sapeva davvero che avrebbe potuto usare il built-in, ma la domanda sembra in realtà riguardare un errore di tipo. Spero comunque che abbia cambiato e usato la tua opzione (a meno che non sia qualcosa di molto specifico) per seguire i principi di DRY e code-economy di base.
JC Rocamonde,

1

In Python 2 dict.keys () restituisce un elenco, mentre in Python 3 restituisce un generatore.

Potresti solo iterare sui suoi valori, altrimenti potresti doverlo convertire esplicitamente in un elenco, ovvero passarlo a una funzione di elenco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.