TypeError: el objeto 'dict_keys' no admite indexación


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]

Cuando ejecuto la shufflefunción, aparece el siguiente error, ¿por qué es eso?

TypeError: 'dict_keys' object does not support indexing

77
parece ser un error de
python3

Respuestas:


231

Claramente estás pasando d.keys()a tu shufflefunción. Probablemente esto fue escrito con python2.x (cuando se d.keys()devuelve una lista). Con python3.x, d.keys()devuelve un dict_keysobjeto que se comporta mucho más como a setque a list. Como tal, no se puede indexar.

La solución es pasar list(d.keys())(o simplemente list(d)) a shuffle.


22
. . . O simplemente, lo list(d)que le dará una lista de claves en python2.xy python3.x sin hacer ninguna copia :-)
mgilson

11
Esta es una extraña decisión de diseño de cambio de ruptura para python3.
Jason

9
Puede pensar que sí, pero definitivamente creo que fue la decisión correcta. El dict_keysobjeto se comporta mucho más como las teclas de la mitad de un dict. Específicamente, admiten pruebas de membresía O (1) (y otros métodos similares a conjuntos que se pueden implementar de manera eficiente además de ese hecho). Estas cosas no son posibles con una lista y si desea una lista de las claves del dict, siempre ha podido hacer list(your_dictionary)para obtenerla.
mgilson

Esto es útil para mí al ver que python3 requiere que envuelvamos el diccionario con la lista.
DataEngineer

2
@Crt: shufflees el nombre de la función en el código del póster original (la función que arroja el error). Al mirar el código, creo que fue copiado / pegado de random.shufflela implementación de la biblioteca estándar :-)
mgilson

11

Estás pasando el resultado de somedict.keys()a la función. En Python 3, dict.keysno devuelve una lista, pero un objeto tipo conjunto que representa una vista de las teclas del diccionario y (al ser tipo conjunto) no admite la indexación.

Para solucionar el problema, use list(somedict.keys())para recoger las claves y trabaje con eso.


10

Convertir un iterable en una lista puede tener un costo. En cambio, para obtener el primer elemento, puede usar:

next(iter(keys))

O, si desea iterar sobre todos los elementos, puede usar:

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

1

¿Por qué necesita implementar shuffle cuando ya existe? Mantente sobre los hombros de los gigantes.

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 respuesta es relevante para el conocimiento general, pero no se refiere a lo que preguntaba el OP.
JC Rocamonde

Tienes razón. Parece que quiere implementar su propio aleatorizador.
FooBar167

1
psah, tal vez en realidad no sabía que podía usar el incorporado, pero la pregunta en realidad parece ser sobre un error de tipo. Aún así, espero que haya cambiado y utilizado su opción (a menos que sea algo muy específico) para seguir los principios básicos de economía de código y DRY.
JC Rocamonde

1

En Python 2, dict.keys () devuelve una lista, mientras que en Python 3 devuelve un generador.

Solo podría iterar sobre sus valores; de lo contrario, tendrá que convertirlo explícitamente en una lista, es decir, pasarlo a una función de lista.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.