Acceso al elemento dict_keys por índice en Python3

131

Estoy tratando de acceder al elemento dict_key por su índice:

test = {'foo': 'bar', 'hello': 'world'}
keys = test.keys()  # dict_keys object

keys.index(0)
AttributeError: 'dict_keys' object has no attribute 'index'

Quiero llegar foo.

lo mismo con:

keys[0]
TypeError: 'dict_keys' object does not support indexing

¿Cómo puedo hacer esto?

fj123x
fuente
9
En py3.x dict.keys()devuelve un conjunto como objeto de vista, no lista (por lo tanto, la indexación no es posible). Usokeys = list(test)
Ashwini Chaudhary
cuando hago una lista (something_dict), el orden de las tuplas es aleatorio: ejemplo: list ({'foo': 'bar', 'hello': 'world'}) puede devolver: list (foo, hello) o list (hello, foo), ¿por qué es esto al azar?
fj123x
77
Los dictados no tienen ningún orden . (Úselo collections.OrderedDictsi desea claves ordenadas)
Ashwini Chaudhary
Una discusión interesante sobre la seguridad de los hilos aquí reagrupando los diversos enfoques para resolver este problema: blog.labix.org/2008/06/27/…
Paul

Respuestas:

161

Llame list()al diccionario en su lugar:

keys = list(test)

En Python 3, el dict.keys()método devuelve un objeto de vista de diccionario , que actúa como un conjunto. Iterar sobre el diccionario directamente también produce claves, por lo que convertir un diccionario en una lista da como resultado una lista de todas las claves:

>>> test = {'foo': 'bar', 'hello': 'world'}
>>> list(test)
['foo', 'hello']
>>> list(test)[0]
'foo'
Martijn Pieters
fuente
3
Tenga cuidado con la lista (dict.keys ()) en Python 3: Labix Blog explica claramente cuál es el problema sin proporcionar una solución. ¡Esto es excelente!
Brandon Bradley
@BrandonBradley: en general: confiar en que ciertas acciones sean atómicas es una mala idea de todos modos, ya que Python es muy dinámico. Su código puede pasar fácilmente una dictsubclase, por ejemplo, donde .keys()se maneja en código Python (por ejemplo, puede tener lugar un cambio de hilo).
Martijn Pieters
@BrandonBradley: gracias por el enlace. Solo la solución de uno de los comentarios para ese blog funciona para mí en Python3: sorted (dict.keys ()). En Python2, dict.keys () devolverá una lista de valores clave.
Buena voluntad
2
@ GoodWill: sorted(dict)haría exactamente lo mismo; producir una lista de claves en orden ordenado. list(dict)le dará la lista en orden de diccionario.
Martijn Pieters
1
o para usarkeys = [*test]
Alex78191
59

No es una respuesta completa, pero quizás una pista útil. Si realmente es el primer elemento que desea *, entonces

next(iter(q))

es mucho más rápido que

list(q)[0]

para dictos grandes, ya que todo no tiene que almacenarse en la memoria.

Por 10,000,000 artículos encontré que es casi 40,000 veces más rápido.

* El primer elemento en caso de que un dict sea solo un elemento pseudoaleatorio antes de Python 3.6 (después de eso se ordena en la implementación estándar, aunque no se recomienda confiar en él).

marca
fuente
55
Este siempre ha sido uno de mis mayores problemas con todo convirtiéndose en iteradores en Py3. Definitivamente es más eficiente, pero muchos casos de uso se vuelven "impuros" y complicados sin ninguna razón. Por ejemplo, ¿por qué no pueden simplemente soportar la indexación en el iterador, sin necesariamente tener una pérdida de rendimiento?
Ehsan Kia
2

Quería el par "clave" y "valor" de un primer elemento del diccionario. Use el siguiente código.

 key, val = next(iter(my_dict.items()))
Sheikh Abdul Wahid
fuente
0
test = {'foo': 'bar', 'hello': 'world'}
ls = []
for key in test.keys():
    ls.append(key)
print(ls[0])

Manera convencional de agregar las claves a una lista estáticamente definida y luego indexarla por la misma

pranav dua
fuente
2
No está mal, pero ¿por qué no ls = list(test.keys())? Lo encuentro más simple.
Valentino
Sí, esto es más eficiente. Escribí esto solo para mostrar la legibilidad.
pranav dua
0

En muchos casos, esto puede ser un problema XY . ¿Por qué indexa las teclas de su diccionario por posición? ¿Realmente lo necesitas? Hasta hace poco, los diccionarios ni siquiera se ordenaban en Python, por lo que acceder al primer elemento era arbitrario.

Acabo de traducir un código de Python 2 a Python 3:

keys = d.keys()
for (i, res) in enumerate(some_list):
    k = keys[i]
    # ...

lo cual no es bonito, pero tampoco está muy mal. Al principio, estaba a punto de reemplazarlo por lo monstruoso

    k = next(itertools.islice(iter(keys), i, None))

antes de darme cuenta de que todo esto está mucho mejor escrito como

for (k, res) in zip(d.keys(), some_list):

que funciona bien

Creo que en muchos otros casos, se puede evitar indexar las claves del diccionario por posición. Aunque los diccionarios están ordenados en Python 3.7, confiar en eso no es bonito. El código anterior solo funciona porque el contenido de some_listha sido producido recientemente a partir del contenido de d.

Observe detenidamente su código si realmente necesita acceder a un disk_keyselemento por índice. Quizás no necesites hacerlo.

gerrit
fuente
0

Prueba esto

keys = [next(iter(x.keys())) for x in test]
print(list(keys))

El resultado se ve así. ['foo', 'hola']

Puede encontrar más soluciones posibles aquí .

Shirantha Madusanka
fuente