La adición de collections.defaultdict
en Python 2.5 reduce en gran medida la necesidad de dict
's setdefault
método. Esta pregunta es para nuestra educación colectiva:
- ¿Para qué sigue
setdefault
siendo útil hoy en Python 2.6 / 2.7? - ¿Con qué casos de uso populares
setdefault
fueron reemplazadoscollections.defaultdict
?
python
dictionary
setdefault
Eli Bendersky
fuente
fuente
Respuestas:
Se podría decir que
defaultdict
es útil para configurar los valores predeterminados antes de completar el dict ysetdefault
es útil para establecer valores predeterminados durante o después de completar el dict .Probablemente el caso de uso más común: elementos de agrupación (en datos no clasificados, de lo contrario, uso
itertools.groupby
)A veces desea asegurarse de que existan claves específicas después de crear un dict.
defaultdict
no funciona en este caso, porque solo crea claves en el acceso explícito. Cree que usa algo HTTP-ish con muchos encabezados; algunos son opcionales, pero desea valores predeterminados para ellos:fuente
defaultdict
. ¿Puedes dar un ejemplo de lo que quieres decir en el primer párrafo?setdefault
. A,defaultdict
por otro lado, no funcionaría si no todosdefaultvalues
son iguales (es decir, algunos son0
y otros son[]
).headers = dict(optional_headers)
. Para el caso en que los valores predeterminados no son todos iguales. Y el resultado final es el mismo que si obtiene los encabezados HTTP primero y luego configure los valores predeterminados para aquellos que no obtuvo. Y es bastante útil si ya lo tienesoptional_headers
. Pruebe mi código de 2 pasos y compárelo con el suyo, y verá lo que quiero decir.new.setdefault(key, []).append(value)
defaultdict
incluso mejor quesetdefault
(¿dónde está el caso de uso ahora?). Además,ChainMap
manejaría mejor elhttp
ejemplo, IMO.Comúnmente uso
setdefault
para dictados de argumentos de palabras clave, como en esta función:Es ideal para ajustar argumentos en contenedores alrededor de funciones que toman argumentos de palabras clave.
fuente
defaultdict
es excelente cuando el valor predeterminado es estático, como una nueva lista, pero no tanto si es dinámico.Por ejemplo, necesito un diccionario para asignar cadenas a entradas únicas.
defaultdict(int)
siempre usará 0 para el valor predeterminado. Asimismo,defaultdict(intGen())
siempre produce 1.En cambio, usé un dict regular:
Tenga en cuenta que
dict.get(key, nextID())
es insuficiente porque también necesito poder hacer referencia a estos valores más adelante.intGen
es una pequeña clase que construyo que incrementa automáticamente un int y devuelve su valor:Si alguien tiene una manera de hacer esto
defaultdict
, me encantaría verlo.fuente
intGen
conitertools.count().next
.nextID()
El valor de 'se incrementará cada vez quemyDict.setdefault()
se llame, incluso si el valor que devuelve no se usa como astrID
. Esto parece un desperdicio de alguna manera e ilustra una de las cosas que no me gustansetdefault()
en general, a saber, que siempre evalúa sudefault
argumento si realmente se usa o no.defaultdict
:myDict = defaultdict(lambda: nextID())
. Más tarde,strID = myDict[myStr]
en el bucle.myDict = defaultdict(nextID)
?Lo uso
setdefault()
cuando quiero un valor predeterminado en unOrderedDict
. No hay una colección estándar de Python que hace las dos cosas, pero no son maneras de implementar una colección tan.fuente
Como la mayoría de las respuestas indican
setdefault
odefaultdict
le permitirían establecer un valor predeterminado cuando no existe una clave. Sin embargo, me gustaría señalar una pequeña advertencia con respecto a los casos de uso desetdefault
. Cuando se ejecuta el intérprete de Pythonsetdefault
, siempre evaluará el segundo argumento de la función, incluso si la clave existe en el diccionario. Por ejemplo:Como puede ver,
print
también se ejecutó aunque 2 ya existían en el diccionario. Esto se vuelve particularmente importante si planea utilizar,setdefault
por ejemplo, una optimización comomemoization
. Si agrega una llamada de función recursiva como segundo argumentosetdefault
, no obtendría ningún rendimiento, ya que Python siempre llamaría a la función de forma recursiva.Como se mencionó la memorización, una mejor alternativa es utilizar el decorador functools.lru_cache si considera mejorar una función con la memorización. lru_cache maneja mejor los requisitos de almacenamiento en caché para una función recursiva.
fuente
Como dijo Muhammad, hay situaciones en las que a veces solo desea establecer un valor predeterminado. Un gran ejemplo de esto es una estructura de datos que primero se completa, luego se consulta.
Considera un trie. Al agregar una palabra, si se necesita un subnodo pero no está presente, debe crearse para extender el trie. Al consultar la presencia de una palabra, un subnodo faltante indica que la palabra no está presente y que no debe crearse.
Un defaultdict no puede hacer esto. En su lugar, se debe utilizar un dict regular con los métodos get y setdefault.
fuente
Teóricamente hablando,
setdefault
aún sería útil si a veces quieres establecer un valor predeterminado y otras no. En la vida real, no me he encontrado con ese caso de uso.Sin embargo, un caso de uso interesante surge de la biblioteca estándar (Python 2.6, _threadinglocal.py):
Yo diría que usar
__dict__.setdefault
es un caso bastante útil.Editar : como sucede, este es el único ejemplo en la biblioteca estándar y está en un comentario. Por lo tanto, puede que no sea un caso suficiente para justificar la existencia de
setdefault
. Aún así, aquí hay una explicación:Los objetos almacenan sus atributos en el
__dict__
atributo. De hecho, el__dict__
atributo se puede escribir en cualquier momento después de la creación del objeto. También es un diccionario, no undefaultdict
. No es sensato que los objetos en el caso general tengan__dict__
como undefaultdict
porque eso haría que cada objeto tenga todos los identificadores legales como atributos. Por lo tanto, no puedo prever ningún cambio en la eliminación de los objetos de Python__dict__.setdefault
, aparte de eliminarlo por completo si no se considera útil.fuente
__dict__
por implementación adict
, no adefaultdict
.setdefault
quedarme en Python, pero es curioso ver que ahora es casi inútil.setdefault
hace explícito que está asignando a un dict a través de una clave que puede existir o no, y si no existe desea que se cree con un valor predeterminado: por ejemplod.setdefault(key,[]).append(value)
. En otra parte del programa que hacealist=d[k]
donde se calcula k, y desea que se arroje una excepción si k no está en d (que con unassert k in d
if not ( k in d): raise KeyError
Un inconveniente de
defaultdict
overdict
(dict.setdefault
) es que undefaultdict
objeto crea un nuevo elemento CADA VEZ que se da una clave no existente (por ejemplo==
, con ,print
). Además, ladefaultdict
clase es generalmente mucho menos común que ladict
clase, es más difícil serializarla IME.Las funciones de PS IMO | métodos no destinados a mutar un objeto, no deben mutar un objeto.
fuente
defaultdict(lambda l=[]: l)
.Estos son algunos ejemplos de setdefault para mostrar su utilidad:
fuente
Reescribí la respuesta aceptada y la facilité para los novatos.
Además, clasifiqué los métodos como referencia:
fuente
Uso setdefault con frecuencia cuando, obtengo esto, establezco un valor predeterminado (!!!) en un diccionario; de alguna manera comúnmente el diccionario os.environ:
Menos sucintamente, esto se ve así:
Vale la pena señalar que también puede usar la variable resultante:
Pero eso es menos necesario de lo que era antes de que existieran los dictados por defecto.
fuente
Otro caso de uso que no creo que se mencionó anteriormente. A veces, mantiene una memoria caché de objetos por su identificación donde la instancia principal está en la memoria caché y desea establecer la memoria caché cuando falta.
Eso es útil cuando siempre desea mantener una única instancia por ID distinta, sin importar cómo obtenga un obj cada vez. Por ejemplo, cuando los atributos del objeto se actualizan en la memoria y se difiere el almacenamiento en el almacenamiento.
fuente
Un caso de uso muy importante con el que me topé:
dict.setdefault()
es ideal para código multiproceso cuando solo desea un único objeto canónico (a diferencia de varios objetos que son iguales).Por ejemplo, el
(Int)Flag
Enum en Python 3.6.0 tiene un error : si varios hilos compiten por un(Int)Flag
miembro compuesto , puede haber más de uno:La solución es usarlo
setdefault()
como el último paso para guardar el miembro compuesto calculado: si ya se ha guardado otro, se usará en lugar del nuevo, garantizando miembros únicos de Enum.fuente
[Editar] Muy mal! Setdefault siempre activaría long_computation, Python ansioso.
Ampliando la respuesta de Tuttle. Para mí, el mejor caso de uso es el mecanismo de caché. En vez de:
que consume 3 líneas y 2 o 3 búsquedas,
felizmente escribiría:fuente
long_computation(x)
solo se llama six not in memo
. Mientras que en el segundo,long_computation(x)
siempre se llama. Solo la asignación es condicional, el código equivalentesetdefault
sería:v = long_computation(x)
/if x not in memo:
/memo[x] = v
.Me gusta la respuesta dada aquí:
http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html
En resumen, la decisión (en aplicaciones que no son críticas para el rendimiento) debe tomarse sobre la base de cómo desea manejar la búsqueda de claves vacías en sentido descendente ( es decir,
KeyError
frente al valor predeterminado).fuente
El caso de uso diferente
setdefault()
es cuando no desea sobrescribir el valor de una clave ya establecida.defaultdict
sobrescribe, mientrassetdefault()
que no. En el caso de los diccionarios anidados, es más frecuente que desee establecer un valor predeterminado solo si la clave aún no está configurada, porque no desea eliminar el actual sub diccionario. Esto es cuando lo usassetdefault()
.Ejemplo con
defaultdict
:setdefault
no sobrescribe:fuente