¿Por qué dict.get (key) en lugar de dict [key]?

651

Hoy, me encontré con el dictmétodo getque, dada una clave en el diccionario, devuelve el valor asociado.

¿Para qué sirve esta función? Si quisiera encontrar un valor asociado con una clave en un diccionario, simplemente puedo hacerlo dict[key], y devuelve lo mismo:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
stensootla
fuente
1
dictionary["foo"]y dictionary.get("foo")comportarse de manera diferente, sin embargo.
Niklas B.
34
dictionary.get("Age") es lo mismo que escribir, dictionary["Age"] or None así que maneja implícitamente la excepción KeyError
yosemite_k
55
@yosemite_k Puede que me falte algo de contexto aquí, pero dictionary['non-existent key'] or Nonedebería y aún plantea un problema KeyErrorpara mí (hasta v3.6). ¿Puedes explicar a qué te refieres?
nivk
@nivk dictionary ['clave inexistente'] genera un error, y ese error debe ser manejado explícitamente. si en su lugar usa dictionary.get () (que literalmente funciona como diccionario ['clave inexistente'] o None), esa excepción se maneja implícitamente.
yosemite_k

Respuestas:

994

Le permite proporcionar un valor predeterminado si falta la clave:

dictionary.get("bogus", default_value)

devuelve default_value(lo que sea que elija), mientras que

dictionary["bogus"]

elevaría a KeyError.

Si se omite, default_valuees Nonetal que

dictionary.get("bogus")  # <-- No default specified -- defaults to None

vuelve Nonecomo

dictionary.get("bogus", None)

haría.

unutbu
fuente
1
¿Sería esto lo mismo que dictionary.get("bogus") or my_default? He visto a personas usarlo en algunos casos y me preguntaba si hay alguna ventaja de usar uno en lugar del otro (aparte de la legibilidad)
Algorithmatic
15
@MustafaS: Si "bogus"es una clave dictionaryy dictionary.get("bogus")devuelve un valor que se evalúa como Falso en un contexto booleano (es decir, un valor de Falsey), como 0 o una cadena vacía '', entonces dictionary.get("bogus") or my_defaultse evaluaría my_defaultmientras dictionary.get("bogus", my_default)que devolvería el valor de Falsey. Entonces no, dictionary.get("bogus") or my_defaultno es equivalente a dictionary.get("bogus", my_default). Cuál usar depende del comportamiento que desee.
unutbu
3
@MustafaS: Por ejemplo, supongamos x = {'a':0}. Luego x.get('a', 'foo')vuelve 0pero x.get('a') or 'foo'vuelve 'foo'.
unutbu
3
Una posible advertencia al usar dictionary.get('key'): puede ser confuso si los valores en el diccionario son None. Sin especificar el valor de retorno (segundo argumento opcional) no hay forma de verificar si la clave no existía o si su valor es None. En este caso específico, consideraría usar try-except-KeyError.
Aart Goossens
1
Vale la pena señalar que la expresión para especificar el valor predeterminado se evalúa en la llamada "get" y, por lo tanto, se evalúa en cada acceso. Una alternativa clásica (utilizando un controlador KeyError o un predicado) es evaluar el valor predeterminado solo si falta la clave. Esto permite crear un cierre / lambda una vez y evaluarlo en cualquier clave faltante.
Tom Stambaugh
142

Cual es el dict.get()metodo

Como ya se mencionó, el getmétodo contiene un parámetro adicional que indica el valor faltante. De la documentación

get(key[, default])

Devuelve el valor de la clave si la clave está en el diccionario, de lo contrario es el valor predeterminado. Si no se proporciona el valor predeterminado, el valor predeterminado es Ninguno, de modo que este método nunca genere a KeyError.

Un ejemplo puede ser

>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1

¿Hay mejoras de velocidad en alguna parte?

Como se menciona aquí ,

Parece que los tres enfoques ahora exhiben un rendimiento similar (dentro de aproximadamente el 10% entre sí), más o menos independientes de las propiedades de la lista de palabras.

Anteriormente getera considerablemente más lento, sin embargo, ahora la velocidad es casi comparable junto con la ventaja adicional de devolver el valor predeterminado. Pero para borrar todas nuestras consultas, podemos probar en una lista bastante grande (tenga en cuenta que la prueba incluye buscar solo todas las claves válidas)

def getway(d):
    for i in range(100):
        s = d.get(i)

def lookup(d):
    for i in range(100):
        s = d[i]

Ahora cronometrando estas dos funciones usando timeit

>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979

Como podemos ver, la búsqueda es más rápida que la obtención, ya que no hay búsqueda de funciones. Esto se puede ver a través dedis

>>> def lookup(d,val):
...     return d[val]
... 
>>> def getway(d,val):
...     return d.get(val)
... 
>>> dis.dis(getway)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_ATTR                0 (get)
              6 LOAD_FAST                1 (val)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE        
>>> dis.dis(lookup)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (val)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE  

¿Dónde será útil?

Será útil siempre que desee proporcionar un valor predeterminado cada vez que busque un diccionario. Esto reduce

 if key in dic:
      val = dic[key]
 else:
      val = def_val

A una sola línea, val = dic.get(key,def_val)

¿Dónde no será útil?

Siempre que desee devolver un mensaje que KeyErrorindique que la clave particular no está disponible. ¡Devolver un valor predeterminado también conlleva el riesgo de que un valor predeterminado particular también sea una clave!

¿Es posible tener getcomo característica en dict['key']?

¡Si! Necesitamos implementar el __missing__en una subclase dict.

Un programa de muestra puede ser

class MyDict(dict):
    def __missing__(self, key):
        return None

Una pequeña demostración puede ser

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
Bhargav Rao
fuente
32
¡El estándar de oro de las respuestas de StackOverflow!
Apollo Data
1
Una prueba más bien sería if k in dict and dict[k]:vs if dict.get(k):. Esto cubre la situación en la que tenemos que comprobar si la clave existe, y si 'sí' - ¿qué valor ?, algo como: dict = {1: '', 2: 'some value'}.
TitanFighter
77
Recuerde que el valor predeterminado se evalúa independientemente del valor que esté en el diccionario, por lo que en lugar de dictionary.get(value, long_function())uno podría considerar usarlodictionary.get(value) or long_function()
Kresimir,
Ah @Kresimir, cierto. Recibí esa pregunta en una de las entrevistas a las que me enfrenté (no lo sabía cuando originalmente publiqué esta respuesta). Gracias por recordarmelo.
Bhargav Rao
32

gettoma un segundo valor opcional. Si la clave especificada no existe en su diccionario, se devolverá este valor.

dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'

Si no proporciona el segundo parámetro, Nonese devolverá.

Si usa la indexación como en dictionary['Year'], las teclas inexistentes aparecerán KeyError.

Ángel caido
fuente
19

Daré un ejemplo práctico en el raspado de datos web usando python, muchas veces obtendrás claves sin valores, en esos casos obtendrás errores si usas dictionary ['key'], mientras dictionary.get ('key ',' return_otherwise ') no tiene problemas.

Del mismo modo, usaría '' .join (list) en lugar de list [0] si intenta capturar un solo valor de una lista.

Espero eso ayude.

[Editar] Aquí hay un ejemplo práctico:

Digamos que está llamando a una API, que devuelve un archivo JOSN que necesita analizar. El primer JSON tiene el siguiente aspecto:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}

El segundo JOSN es así:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}

Tenga en cuenta que al segundo JSON le falta la clave "submitdate_ts", que es bastante normal en cualquier estructura de datos.

Entonces, cuando intentas acceder al valor de esa clave en un bucle, ¿puedes llamarlo con lo siguiente?

for item in API_call:
    submitdate_ts = item["bids"]["submitdate_ts"]

Podría, pero le dará un error de rastreo para la segunda línea JSON, porque la clave simplemente no existe.

La forma apropiada de codificar esto podría ser la siguiente:

for item in API_call:
    submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")

{'x': Ninguno} está ahí para evitar que el segundo nivel obtenga un error. Por supuesto, puede incorporar más tolerancia a fallas en el código si está haciendo scraping. Como primero especificando una condición if

Kevin
fuente
2
Una buena respuesta, publicada antes que cualquiera de los otros, que habría sido votada más, y probablemente aceptada, si hubiera publicado algunos ejemplos de código (sin embargo, +1 de mi parte)
Mawg dice que reinstale a Monica el
2
@Mawg Recientemente tuve un proyecto de raspado para mi investigación. Estaba llamando a una API y analizando básicamente los archivos JSON. Tuve mi RA hacerlo. Uno de los problemas clave que tuvo fue llamar a la tecla directamente, cuando en realidad faltan muchas claves. Publicaré un ejemplo en el texto anterior.
Kevin
¡Gracias por abordar el aspecto multidimensional de esto! Parece que incluso puedes hacer {} en lugar de {'x': Ninguno}
bluppfisk
17

El propósito es que puede dar un valor predeterminado si no se encuentra la clave, lo cual es muy útil

dictionary.get("Name",'harry')
hackartist
fuente
8

¿Para qué sirve esta función?

Un uso particular es contar con un diccionario. Supongamos que desea contar el número de ocurrencias de cada elemento en una lista dada. La forma común de hacerlo es hacer un diccionario donde las claves son elementos y los valores son el número de ocurrencias.

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

Usando el .get()método, puede hacer que este código sea más compacto y claro:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1
jetpack_guy
fuente
7

Hay que tener en cuenta al usar .get() :

Si el diccionario contiene la clave utilizada en la llamada a .get()y su valor es None, el .get()método devolveráNone incluso si se proporciona un valor predeterminado.

Por ejemplo, los siguientes retornos None, no 'alt_value'como se puede esperar:

d = {'key': None}
d.get('key', 'alt_value')

.get()El segundo valor solo se devuelve si la clave suministrada NO está en el diccionario, no si el valor devuelto de esa llamada sí lo está None.

Colton Hicks
fuente
1
Este me consiguió: \ Una forma de resolver esto es tener d.get('key') or 'alt_value'si sabe que podría serNone
Daniel Holmes
4

¿Por qué dict.get (key) en lugar de dict [key]?

0. Resumen

En comparación con dict[key], dict.getproporciona un valor de reserva al buscar una clave.

1. Definición

get (clave [, predeterminado]) 4. Tipos incorporados: documentación de Python 3.6.4rc1

Devuelve el valor de la clave si la clave está en el diccionario; de lo contrario, es el valor predeterminado. Si no se proporciona el valor predeterminado, el valor predeterminado es Ninguno, por lo que este método nunca genera un KeyError.

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Problema que resuelve.

Si no es así default value, debe escribir códigos engorrosos para manejar dicha excepción.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

Como una solución conveniente, dict.getintroduce un valor predeterminado opcional que evita los códigos anteriores de manera involuntaria.

3. Conclusión

dict.get tiene una opción de valor predeterminado adicional para tratar la excepción si la clave está ausente del diccionario

Cálculo
fuente
0

Una diferencia, que puede ser una ventaja, es que si buscamos una clave que no existe, obtendremos None, no como cuando usamos la notación de corchetes, en cuyo caso obtendremos un error:

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

Lo último que tiene de bueno el método get es que recibe un argumento opcional adicional para un valor predeterminado, es decir, si tratamos de obtener el valor de puntaje de un estudiante, pero el estudiante no tiene una clave de puntaje que podamos obtener un 0 en su lugar.

Entonces, en lugar de hacer esto (o algo similar):

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Podemos hacer esto:

score = dictionary.get("score", 0)
# score = 0
אנונימי
fuente
-1

Basado en el uso debe utilizar este getmétodo.

Ejemplo 1

In [14]: user_dict = {'type': False}

In [15]: user_dict.get('type', '')

Out[15]: False

In [16]: user_dict.get('type') or ''

Out[16]: ''

Ejemplo2

In [17]: user_dict = {'type': "lead"}

In [18]: user_dict.get('type') or ''

Out[18]: 'lead'

In [19]: user_dict.get('type', '')

Out[19]: 'lead'
Muthuvel
fuente