Python actualiza una clave en dict si no existe

Respuestas:

144

No necesitas llamar d.keys(), entonces

if key not in d:
    d[key] = value

es suficiente. No existe un método más claro y legible.

Puede actualizar nuevamente con dict.get(), lo que devolvería un valor existente si la clave ya está presente:

d[key] = d.get(key, value)

pero recomiendo encarecidamente no hacerlo; esto es golf de código, lo que dificulta el mantenimiento y la legibilidad.

Martijn Pieters
fuente
¿Necesito sincronizar esto si tengo varios hilos usando el código?
ed22
1
@ ed22 sí, porque consta de múltiples instrucciones de código de bytes, entre las cuales pueden cambiar los hilos.
Martijn Pieters
77

Utilizar dict.setdefault():

>>> d = {1: 'one'}
>>> d.setdefault(1, '1')
'one'
>>> d    # d has not changed because the key already existed
{1: 'one'}
>>> d.setdefault(2, 'two')
'two'
>>> d
{1: 'one', 2: 'two'}
mhawke
fuente
5
dict.setdefault()realmente solo debería usarse cuando se intenta acceder al valor también.
Martijn Pieters
12
@MartijnPieters: ¿por qué importa eso? El nombre setdefault()describe claramente lo que está sucediendo, que también devuelve un valor que no es tan importante y, en mi opinión, un poco peculiar. ¿Podría darnos una explicación rápida, o un enlace a alguna, de por qué esto no es deseable?
mhawke
6
Tendrá que utilizar en una expresión que se espera que exista un valor, como en un bucle de agrupación: for obj in iterable: d.setdefault(key_for_obj(obj), []).append(obj). No hay nada peculiar en el valor que se devuelve, ese es el objetivo del método .
Martijn Pieters
2
Además, oculta lo que está tratando de hacer, que es establecer una clave solo si aún no está presente. La legibilidad cuenta, solo use una if key not in d:prueba.
Martijn Pieters
6
@MartijnPieters: Gracias por la explicación. Después de leer la cadena de documentos, setdefault()parece estar orientado a lo que ha dicho. El uso de un defaultdict(list)daría como resultado un código más legible que su ejemplo ... así que quizás no sea útil a menos que uno deba trabajar con diccionarios estándar. En general, if key not in des más claro.
mhawke
22

Desde Python 3.9 , puede usar el operador | de combinación para combinar dos diccionarios. El dictamen de la derecha tiene prioridad:

d = { key: value } | d

Nota: esto crea un nuevo diccionario con los valores actualizados.

Rotareti
fuente
4
Si bien esto es interesante, no creo que sea más legible que la respuesta aceptada
Justin Furuness
Para mí, es bueno saber que hay una manera de fusionar dos dictados ahora
Austin A
5

Con lo siguiente, puede insertar varios valores y también tener valores predeterminados, pero está creando un nuevo diccionario.

d = {**{ key: value }, **default_values}

Lo he probado con la respuesta más votada y, en promedio, es más rápido, como se puede ver en el siguiente ejemplo:.

Prueba de velocidad que compara un método basado en bucle for con una comprensión de dictado con operador de desempaque Prueba de velocidad que compara un método basado en bucle for con una comprensión de dictado con un método de operador de desempaquetado.

si no d = default_vals.copy()se realiza ninguna copia ( ) en el primer caso, la respuesta más votada sería más rápida una vez que alcancemos órdenes de magnitud de 10**5y mayores. La huella de memoria de ambos métodos es la misma.

CoderKid
fuente
1
Entonces, ¿por qué sugerirlo en primer lugar
Jonathan
1
Esta solución me parece perfectamente válida. También permite actualizar múltiples valores en una declaración.
Rotareti
Muchas gracias. Pero parece que debería ser{**default_values, **{ key: value }}
osexp2003
0

De acuerdo con las respuestas anteriores, el método setdefault () funcionó para mí.

old_attr_name = mydict.setdefault(key, attr_name)
if attr_name != old_attr_name:
    raise RuntimeError(f"Key '{key}' duplication: "
                       f"'{old_attr_name}' and '{attr_name}'.")

Aunque esta solución no es genérica. Simplemente me convenía en este caso concreto. La solución exacta sería verificar la keyprimera (como ya se aconsejó), pero con setdefault()evitamos una búsqueda adicional en el diccionario, es decir, aunque pequeña, pero aún así una ganancia de rendimiento.

usuario10815638
fuente