Respuestas:
Me gusta esto:
host = connectionDetails.get('host', someDefaultValue)
if/else
es mucho más rápido. Eso podría o no jugar un papel.
if/else
es más rápido?
También puede usar el me defaultdict
gusta así:
from collections import defaultdict
a = defaultdict(lambda: "default", key="some_value")
a["blabla"] => "default"
a["key"] => "some_value"
Puede pasar cualquier función ordinaria en lugar de lambda:
from collections import defaultdict
def a():
return 4
b = defaultdict(a, key="some_value")
b['absent'] => 4
b['key'] => "some_value"
get
métodos similares.
Si bien .get()
es un buen lenguaje, es más lento que if/else
(y más lento que try/except
si la presencia de la clave en el diccionario se puede esperar la mayor parte del tiempo):
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.07691968797894333
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.4583777282275605
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="a=d.get(1, 10)")
0.17784020746671558
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="a=d.get(2, 10)")
0.17952161730158878
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.10071221458065338
>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.06966537335119938
if/then
sería más rápido. Ambos casos requieren una búsqueda de diccionario, ya menos que la invocación de get()
es manera mucho más lenta, lo que las cuentas de los demás por la desaceleración?
O(1)
independiente del tamaño del diccionario, por lo que la sobrecarga de llamadas de función es relevante.
Para múltiples valores predeterminados diferentes, intente esto:
connectionDetails = { "host": "www.example.com" }
defaults = { "host": "127.0.0.1", "port": 8080 }
completeDetails = {}
completeDetails.update(defaults)
completeDetails.update(connectionDetails)
completeDetails["host"] # ==> "www.example.com"
completeDetails["port"] # ==> 8080
None
o la emptyString como uno de los valores en los pares clave-valor. El defaults
diccionario podría potencialmente tener uno de sus valores borrados involuntariamente. (ver también stackoverflow.com/questions/6354436 )
Hay un método en los diccionarios de Python para hacer esto: dict.setdefault
connectionDetails.setdefault('host',someDefaultValue)
host = connectionDetails['host']
Sin embargo, este método establece el valor de connectionDetails['host']
a someDefaultValue
si la clave aún host
no está definida, a diferencia de lo que se hizo la pregunta.
setdefault()
el valor devoluciones, así que esto funciona así: host = connectionDetails.setdefault('host', someDefaultValue)
. Solo tenga en cuenta que se establecerá connectionDetails['host']
en el valor predeterminado si la clave no estaba allí antes.
(esta es una respuesta tardía)
Una alternativa es subclasificar la dict
clase e implementar el __missing__()
método, así:
class ConnectionDetails(dict):
def __missing__(self, key):
if key == 'host':
return "localhost"
raise KeyError(key)
Ejemplos:
>>> connection_details = ConnectionDetails(port=80)
>>> connection_details['host']
'localhost'
>>> connection_details['port']
80
>>> connection_details['password']
Traceback (most recent call last):
File "python", line 1, in <module>
File "python", line 6, in __missing__
KeyError: 'password'
Al probar la sospecha de @Tim Pietzcker sobre la situación en PyPy (5.2.0-alpha0) para Python 3.3.5, encuentro que, de hecho, ambos .get()
y if
/ else
way funcionan de manera similar. En realidad, parece que en el caso if / else hay incluso una sola búsqueda si la condición y la asignación involucran la misma clave (compárese con el último caso donde hay dos búsquedas).
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[1]\nexcept KeyError:\n a=10")
0.011889292989508249
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="try:\n a=d[2]\nexcept KeyError:\n a=10")
0.07310474599944428
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(1, 10)")
0.010391917996457778
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="a=d.get(2, 10)")
0.009348208011942916
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 1 in d:\n a=d[1]\nelse:\n a=10")
0.011475925013655797
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=10")
0.009605801998986863
>>>> timeit.timeit(setup="d={1:2, 3:4, 5:6, 7:8, 9:0}",
.... stmt="if 2 in d:\n a=d[2]\nelse:\n a=d[1]")
0.017342638995614834
Puede usar una función lamba para esto como una línea. Cree un nuevo objeto al connectionDetails2
que se acceda como una función ...
connectionDetails2 = lambda k: connectionDetails[k] if k in connectionDetails.keys() else "DEFAULT"
Ahora usa
connectionDetails2(k)
en vez de
connectionDetails[k]
que devuelve el valor del diccionario si k
está en las claves; de lo contrario, devuelve"DEFAULT"