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?


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'

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).


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()))

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


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.


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í .

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.