TypeError: l'objet 'dict_keys' ne prend pas en charge l'indexation

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]

Lorsque j'exécute la shufflefonction, cela génère l'erreur suivante, pourquoi?

TypeError: 'dict_keys' object does not support indexing
gate_007
la source
7
semble être une erreur python3
DataEngineer

Réponses:

231

De toute évidence, vous passez d.keys()à votre shufflefonction. Cela a probablement été écrit avec python2.x (lorsque d.keys()renvoyé une liste). Avec python3.x, d.keys()renvoie un dict_keysobjet qui se comporte beaucoup plus comme setunlist . En tant que tel, il ne peut pas être indexé.

La solution est de passer list(d.keys())(ou simplement list(d)) à shuffle.

mgilson
la source
22
. . . Ou juste list(d)ce qui vous donnera une liste de clés sur python2.x et python3.x sans faire de copies :-)
mgilson
11
C'est une étrange décision de conception de changement de rupture pour python3.
Jason
9
Vous pourriez le penser, mais je pense vraiment que c'était la bonne décision. L' dict_keysobjet se comporte beaucoup plus comme juste la moitié des clés d'un dict. Plus précisément, ils prennent en charge les tests d'appartenance O (1) (et d'autres méthodes de type ensemble qui peuvent être mises en œuvre efficacement en plus de ce fait). Ces choses ne sont pas possibles avec une liste et si vous voulez une liste des clés du dict, vous avez toujours été capable de faire simplement list(your_dictionary)pour l'obtenir.
mgilson
cela m'aide à voir que python3 nous oblige à envelopper le dictionnaire avec list.
DataEngineer
2
@Crt - shuffleest le nom de la fonction dans le code de l'affiche d'origine (la fonction qui génère l'erreur). En regardant le code, je pense qu'il a été copié / collé à partir random.shufflede l'implémentation de la bibliothèque standard :-)
mgilson
11

Vous passez le résultat de somedict.keys()à la fonction. Dans Python 3, dict.keysne renvoie pas de liste, mais un objet de type set qui représente une vue des clés du dictionnaire et (étant de type set) ne prend pas en charge l'indexation.

Pour résoudre le problème, utilisez list(somedict.keys())pour récupérer les clés et travaillez avec cela.

user4815162342
la source
10

La conversion d'un itérable en liste peut avoir un coût. Au lieu de cela, pour obtenir le premier élément, vous pouvez utiliser:

next(iter(keys))

Ou, si vous souhaitez parcourir tous les éléments, vous pouvez utiliser:

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

Pourquoi devez-vous implémenter le shuffle alors qu'il existe déjà? Restez sur les épaules des géants.

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
la source
La réponse est pertinente pour les connaissances générales, mais elle ne répond pas à ce que le PO demandait.
JC Rocamonde
Vous avez raison. Il semble qu'il souhaite implémenter son propre randomiseur.
FooBar167
1
psah, peut-être qu'il ne savait pas vraiment qu'il pouvait utiliser la fonction intégrée, mais la question semble en fait concerner une erreur de type. Pourtant, j'espère qu'il a changé et utilisé votre option (à moins que ce ne soit quelque chose de très spécifique) pour suivre les principes de base de DRY et d'économie de code.
JC Rocamonde
1

En Python 2, dict.keys () renvoie une liste, alors qu'en Python 3, il renvoie un générateur.

Vous ne pouvez itérer que sur ses valeurs, sinon vous devrez peut-être le convertir explicitement en liste, c'est-à-dire le passer à une fonction de liste.

DeWil
la source